kostja
kostja

Reputation: 61578

How to retrieve the datasource used by a persistence unit programmatically

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

Upvotes: 27

Views: 67207

Answers (10)

Shrip
Shrip

Reputation: 181

I tried passing EntityfactoryBeanFactory name in PersistenceContext as unitName and it worked.

Below is an example.

@Configuration
@EnableJpaRepositories(
        basePackages = "com.example.user.repository",
        entityManagerFactoryRef = "userEntityManagerFactory",
        dataSourceRef = "userDataSource",
        transactionManagerRef = "userTransactionManager"
)
public class UserDatasourceConfiguration {

    // Primary data source configuration
    @Primary
    @Bean(name = "userDataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create()
                .build();
    }

    // Configuration properties for the primary data source
    @Primary
    @Bean(name = "userProperties")
    @ConfigurationProperties("spring.datasource")
    public DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }

    // EntityManagerFactory for the primary data source
    @Primary
    @Bean(name = "userEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            EntityManagerFactoryBuilder builder,
            DataSource dataSource) {
        return builder
                .dataSource(dataSource)
                .packages("com.example.user.model")
                .persistenceUnit("user")
                .build();
    }
}

Create UserService class and use PersistenceContext.

class UserService {
    @PersistenceContext(unitName="userEntityManagerFactory")
    EntityManager entityManager;
}

It worked for me. I had two different data source.

Upvotes: 0

Lukasz Ochmanski
Lukasz Ochmanski

Reputation: 1210

in SpringBoot environment you can use the following:

@PersistenceContext
EntityManager entityManager;

private HikariDataSource getDataSourceFromHibernateEntityManager() {
    EntityManagerFactoryInfo info = (EntityManagerFactoryInfo) entityManager.getEntityManagerFactory();
    return (HikariDataSource) info.getDataSource();
}

public String getDataSourceProperties() {
    HikariDataSource dataSource = getDataSourceFromHibernateEntityManager();
    return "DataSource properties:" +
            "URL: " + dataSource.getJdbcUrl() + "\n" +
            "Default Schema: " + dataSource.getPoolName() + "\n" +
            "Driver Class Name: " + dataSource.getDriverClassName() + "\n" +
            "Username: " + dataSource.getUsername() + "\n";
}

Upvotes: 1

DataSource dataSource = (DataSource) 
em.getEntityManagerFactory().getProperties()
            .get(org.hibernate.cfg.AvailableSettings.JPA_JTA_DATASOURCE);

You can retrieve datasoure with hibernate. Tested with Hibernate 5.3

Upvotes: 1

Mikie Mike
Mikie Mike

Reputation: 29

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

Upvotes: -1

Youness
Youness

Reputation: 2080

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

Upvotes: 10

Zach-M
Zach-M

Reputation: 2237

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;

Upvotes: 3

JDGuide
JDGuide

Reputation: 6525

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

Upvotes: 4

Markus Umefjord
Markus Umefjord

Reputation: 201

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

Upvotes: 20

Augusto
Augusto

Reputation: 30007

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.

Upvotes: 23

Steve Ebersole
Steve Ebersole

Reputation: 9443

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.

Upvotes: 9

Related Questions