Hibernate 如何以编程方式检索持久化单元使用的数据源

Hibernate 如何以编程方式检索持久化单元使用的数据源,hibernate,jakarta-ee,jpa,jpa-2.0,jboss7.x,Hibernate,Jakarta Ee,Jpa,Jpa 2.0,Jboss7.x,…而不实际读取和解析persistence.xml 我可以使用。我可以使用来检索可用的数据源。但是我没有发现任何API可以为我提供特定EntityManager的数据源 一个带有名称的字符串就足够了 多谢各位 我正在JBoss7.1.1.Final上使用Hibernate4.0.1.Final,而不是JPA2 编辑:如果可能的话,我希望避免从JPA转向HibernateAPI 编辑:Augusto的解决方案成功了,我有一些关于细节的说明:EM的强制转换不起作用,因为出现了ClassCastExc

…而不实际读取和解析
persistence.xml

我可以使用。我可以使用来检索可用的数据源。但是我没有发现任何API可以为我提供特定
EntityManager
的数据源

一个带有名称的
字符串就足够了

多谢各位

我正在JBoss7.1.1.Final上使用Hibernate4.0.1.Final,而不是JPA2

编辑:如果可能的话,我希望避免从JPA转向HibernateAPI

编辑:Augusto的解决方案成功了,我有一些关于细节的说明:EM的强制转换不起作用,因为出现了
ClassCastException
:(
org.jboss.as.jpa.container.TransactionScopedentialManager不能强制转换为org.hibernate.ejb.EntityManagerImpl
),但它对检索到的工厂有效。所以我省略了第一步

我也找不到从实例中检索数据源名称的方法。所以我不得不满足于目录名:
connectionProvider.getConnection().getCatalog()

您需要:

  • EntityManager
    强制转换为
    EntityManagerImpl
    (Hibernate实现)
  • 调用
    getFactory()
  • EntityManagerFactory
    强制转换为
    HibernateEntityManagerFactory
  • 调用
    getSessionFactory()
    并将其强制转换为
    SessionFactoryImpl
  • 调用
    getConnectionProvider()
    并将其强制转换为正确的实现。您可以看到实现。我假设它是一个
    数据源连接提供程序
  • 调用
    getDataSource()
    就完成了

  • 不幸的是,您必须使用Hibernate API,因为无法使用JPA API检索数据源。

    如果您只需要数据源的名称,并且该数据源名称是按照JPA方式提供的,您应该能够通过以下方式获取该信息:

    entityManager.getEntityManagerFactory().getProperties().get( "javax.persistence.jtaDataSource" );
    


    取决于您如何定义数据源。

    为了运行Flyway迁移,我需要这样做。我无法使用Augusto的方法检索数据源,但我可以通过从SessionFactory属性检索url、用户名和密码来重新创建数据源:

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

    在Spring环境中,您可以使用:

    import org.springframework.orm.jpa.EntityManagerFactoryInfo;
    ...
    
    @PersistenceContext
    EntityManager entityManager;
    
    public DataSource getDataSourceFromHibernateEntityManager() {
       EntityManagerFactoryInfo info = (EntityManagerFactoryInfo) entityManager.getEntityManagerFactory();
       return info.getDataSource();
    }
    
    试试这个:

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

    我正在使用Hibernate5.0.x

    以下是我从持久性池获取连接的方式:

    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();
    }
    
    emf
    参数是JPA的标准
    javax.persistence.EntityManagerFactory
    ,通常通过以下方式全局获取:

    emf = Persistence.createEntityManagerFactory("persistence-unit-name");
    
    或通过注射:

    @PersistenceUnit(unitName="persistence-unit-name")
    EntityManagerFactory emf;
    

    我正在使用hibernate 5.2.10.Final,以下内容对我有用:

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

    您需要的只是将entityManager.getEntityManagerFactory()传递给此方法(在我的情况下,我有多个工厂。然后在需要时,我可以使用此方法获取其中任何工厂的数据源)。

    以下是帮助我的方法。我使用HikariCP,但我认为这不重要

    基本上需要做的是

  • 查找服务注册表
  • 通过
    org.hibernate.engine.jdbc.connections.spi.ConnectionProvider
    类获取服务
  • 将其展开到
    javax.sql.DataSource
  • 可以从EntityManager检索服务注册表

    ((SessionImpl) em).getFactory().getServiceRegistry()
    
    或直接从EntityManagerFactory获取

    ((SessionFactoryImpl) entityManagerFactory).getServiceRegistry()
    

    您可以使用hibernate检索数据源。在SpringBoot环境中使用Hibernate 5.3进行测试,您可以使用以下各项:

    @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";
    }
    

    谢谢,奥古斯托,看起来很有希望。我仍在努力摆脱依赖地狱,试图找出jboss实际提供了哪些hibernate工件来在我的pom中引用它们。在我看来,一旦我看到光明,我会接受对JPA的另一次打击。。。这个过程虽然正确,但比必要的复杂得多。getConnectionProvider()现在似乎已从API中删除。在我的例子中,有
    C3P0ConnectionProvider
    (不是
    DatasourceConnectionProvider
    )没有
    getDataSource()
    方法。通过阅读源代码,找到以下解决方案:
    sessionFactory.getConnectionProvider().unwrap(DataSource.class)
    对我不起作用:(两个查询都返回
    null
    。您是否碰巧有这些属性名称的来源?来源?不确定您的意思。JPA规范定义了它们。这就是您的意思吗?是的,我想我可以尝试一些其他属性。找到了spot-§9.4.3持久性单元属性。据我所知,因为设置这些属性是非常重要的。)不是必需的,它们可能会被提供程序取消设置。Hibernate可能是这样吗?我认为这应该是可行的。如果不是这样,我希望确保它可行。抱歉,我以为已经是这样了。此属性在Hibernate中起作用(我在Hibernate 4.1中尝试过):
    entityManager.GetEntityManager().getProperties().get(“hibernate.connection.datasource”);
    No,No。使用不同的
    datasource
    (甚至指向同一个数据库)可能会导致非常微妙的问题。请编辑您的答案并添加一些上下文来描述您的答案如何解决OP的问题。
    DataSource dataSource = (DataSource) 
    em.getEntityManagerFactory().getProperties()
                .get(org.hibernate.cfg.AvailableSettings.JPA_JTA_DATASOURCE);
    
    @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";
    }