...without actually reading and parsing the persistence.xml
I can retrieve the name of the persistence unit of an EntityManager using the properties of it's factory. I can retrieve the available datasources using the jboss-as-controller-client. But I have found no API that would give me the datasource of a particular EntityManager.
A String with a name would be enough.
Thank you
I am working with Hibernate 4.0.1.Final over JPA 2 on a JBoss 7.1.1.Final.
EDIT: and I would like to avoid straying from JPA to Hibernate APIs if possible.
EDIT : Augusto's solution worked, I have some notes on details: The casting of the EM didn't work because of a ClassCastException:(org.jboss.as.jpa.container.TransactionScopedEntityManager cannot be cast to org.hibernate.ejb.EntityManagerImpl), but it worked for the retrieved factory. So I omitted step 1.
I also could not find a way to retrieve the name of the datasource from the instance. So I had to content myself with the catalog name: connectionProvider.getConnection().getCatalog();
You need to:
- cast the
EntityManagertoEntityManagerImpl(the Hibernate implementation) - call
getFactory() - cast the
EntityManagerFactorytoHibernateEntityManagerFactory - call
getSessionFactory()and cast it toSessionFactoryImpl - call
getConnectionProvider()and cast it to the correct implementation. You can see the implementations here. I'll assume that it's aDatasourceConnectionProvider - call
getDataSource()and you're done.
Unfortunately, you must use the Hibernate API, as there's no way to retrieve the DataSource using the JPA API.
In a Spring environment you can use this:
import org.springframework.orm.jpa.EntityManagerFactoryInfo;
...
@PersistenceContext
EntityManager entityManager;
public DataSource getDataSourceFromHibernateEntityManager() {
EntityManagerFactoryInfo info = (EntityManagerFactoryInfo) entityManager.getEntityManagerFactory();
return info.getDataSource();
}
If you just want the name of the datasource and that datasource name was supplied per JPA means, you should be able to get that information via:
entityManager.getEntityManagerFactory().getProperties().get( "javax.persistence.jtaDataSource" );
or
entityManager.getEntityManagerFactory().getProperties().get( "javax.persistence.nonJtaDataSource" );
depending on how you defined the datasource.
I needed to do this in order to run Flyway migrations. I wasn't able to retrieve the DataSource using Augusto's method, but I was able to recreate the data source by retrieving the url, username & password from the SessionFactory properties:
SessionFactory sessionFactory = ((HibernateEntityManagerFactory) entityManagerFactory).getSessionFactory();
Properties properties = ((SessionFactoryImpl) sessionFactory).getProperties();
String url = (String) properties.get("hibernate.connection.url");
String username = (String) properties.get("hibernate.connection.username");
String password = (String) properties.get("hibernate.connection.password");
Try this :
Session s = (Session) getEntityManager().getDelegate();
org.hibernate.SessionFactory sessionFactory=s.getSessionFactory();
ConnectionProvider cp=((SessionFactoryImpl)sessionFactory).getConnectionProvider();Connection connection=cp.getConnection();
DatabaseMetaData dbmetadata= connection.getMetaData();
String dtsource=dbmetadata.getUserName();
I'm using Hibernate 5.0.x
This is how I'm getting a connection from the persistence pool:
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.jpa.internal.EntityManagerFactoryImpl;
public Connection getConnection(EntityManagerFactory emf) throws SQLException
{
final EntityManagerFactoryImpl hibernateEmf = (EntityManagerFactoryImpl) emf;
return hibernateEmf.getSessionFactory().getServiceRegistry().getService(ConnectionProvider.class).getConnection();
}
The emf parameter is JPA's standard javax.persistence.EntityManagerFactory, typically acquired globally using:
emf = Persistence.createEntityManagerFactory("persistence-unit-name");
or by injection:
@PersistenceUnit(unitName="persistence-unit-name")
EntityManagerFactory emf;
I am using hibernate 5.2.10.Final and the following worked for me:
import org.hibernate.SessionFactory;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
//...
public static DataSource getDataSource(EntityManagerFactory entityManagerFactory) {
ConnectionProvider cp = ((SessionFactory) entityManagerFactory).getSessionFactoryOptions()
.getServiceRegistry()
.getService(ConnectionProvider.class);
return cp.unwrap(DataSource.class);
}
What you need is just to pass entityManager.getEntityManagerFactory() to this method (For my case, I have multiple factories. Then I can use this method to get the datasource for any of them when needed).
Here's what helped me. I use HikariCP but I don't think it matters.
Basically what needs to be done is
- find a service registry
- get service by
org.hibernate.engine.jdbc.connections.spi.ConnectionProviderclass - unwrap it to
javax.sql.DataSource.
Service registry can be retrieved from EntityManager
((SessionImpl) em).getFactory().getServiceRegistry()
or from EntityManagerFactory directly
((SessionFactoryImpl) entityManagerFactory).getServiceRegistry()
来源:https://stackoverflow.com/questions/12423930/how-to-retrieve-the-datasource-used-by-a-persistence-unit-programmatically