How to retrieve the datasource used by a persistence unit programmatically

54,842

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

Solution 2

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

Solution 3

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.

Solution 4

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

Solution 5

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");
Share:
54,842
kostja
Author by

kostja

We are here to learn :) Works and plays with scala, kafka, data, linux

Updated on June 13, 2021

Comments

  • kostja
    kostja almost 3 years

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