How to retrieve the datasource used by a persisten

2019-01-17 01:52发布

问题:

...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();

回答1:

You need to:

  1. cast the EntityManager to EntityManagerImpl (the Hibernate implementation)
  2. call getFactory()
  3. cast the EntityManagerFactory to HibernateEntityManagerFactory
  4. call getSessionFactory() and cast it to SessionFactoryImpl
  5. call getConnectionProvider() and cast it to the correct implementation. You can see the implementations here. I'll assume that it's a DatasourceConnectionProvider
  6. 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.



回答2:

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.



回答3:

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();
}


回答4:

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");


回答5:

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();


回答6:

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;


回答7:

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).



回答8:

Here's what helped me. I use HikariCP but I don't think it matters.

Basically what needs to be done is

  1. find a service registry
  2. get service by org.hibernate.engine.jdbc.connections.spi.ConnectionProvider class
  3. unwrap it to javax.sql.DataSource.

Service registry can be retrieved from EntityManager

((SessionImpl) em).getFactory().getServiceRegistry()

or from EntityManagerFactory directly

((SessionFactoryImpl) entityManagerFactory).getServiceRegistry()