【问题标题】:How to retrieve the datasource used by a persistence unit programmatically如何以编程方式检索持久性单元使用的数据源
【发布时间】:2012-09-14 11:48:26
【问题描述】:

...没有实际读取和解析persistence.xml

我可以使用properties of it's factory 检索EntityManager 的持久性单元的名称。我可以使用jboss-as-controller-client 检索可用的数据源。但我没有发现任何 API 可以为我提供特定 EntityManager 的数据源。

一个有名字的String就足够了。

谢谢

我正在 JBoss 7.1.1.Final 上使用 Hibernate 4.0.1.Final 而不是 JPA 2。

编辑:如果可能的话,我想避免从 JPA 转向 Hibernate API。

编辑:Augusto 的解决方案有效,我对细节有一些说明:由于ClassCastException:(org.jboss.as.jpa.container.TransactionScopedEntityManager cannot be cast to org.hibernate.ejb.EntityManagerImpl),EM 的铸造不起作用,但它适用于检索到的工厂。所以我省略了第 1 步。

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

【问题讨论】:

    标签: hibernate jakarta-ee jpa jpa-2.0 jboss7.x


    【解决方案1】:

    我正在使用休眠 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() 传递给此方法(就我而言,我有多个工厂。然后我可以在需要时使用此方法获取其中任何一个的数据源)。

    【讨论】:

      【解决方案2】:

      在 Spring 环境中你可以使用这个:

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

      【讨论】:

        【解决方案3】:

        你需要:

        1. EntityManager 转换为EntityManagerImpl(Hibernate 实现)
        2. 致电getFactory()
        3. EntityManagerFactory 转换为HibernateEntityManagerFactory
        4. 调用getSessionFactory()并将其转换为SessionFactoryImpl
        5. 调用getConnectionProvider() 并将其转换为正确的实现。你可以看到实现here。我假设它是DatasourceConnectionProvider
        6. 致电getDataSource() 即可完成。

        很遗憾,您必须使用 Hibernate API,因为无法使用 JPA API 检索 DataSource。

        【讨论】:

        • 谢谢,Augusto,看起来很有希望。我仍在努力摆脱依赖地狱,试图找出 jboss 实际提供哪些休眠工件来在我的 pom.xml 中引用它们。看到光明我就接受了
        • 我认为对 JPA 的另一次打击......这个过程虽然正确,但比必要的复杂得多。
        • getConnectionProvider() 现在似乎已从 API 中删除。
        • 就我而言,C3P0ConnectionProvider(不是DatasourceConnectionProvider)没有getDataSource() 方法。通过阅读源码,找到这个解决方案:sessionFactory.getConnectionProvider().unwrap(DataSource.class)
        【解决方案4】:

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

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

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

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

        【讨论】:

        • 对我不起作用 :( 两个查询都返回 null。你碰巧有这些属性名称的来源吗?
        • 来源?不明白你的意思。 JPA 规范定义了它们。是这个意思吗?
        • 是的,我想我可以尝试一些其他属性。找到了现场 - §9.4.3 Persistence Unit Properties。据我了解,由于不需要设置这些属性,因此提供者可能未设置它们。 Hibernate 会是这样吗?
        • 这是我认为应该工作的东西。如果不是,我想确保它确实如此。 hibernate.atlassian.net/browse/HHH-8121对不起,我以为已经是这样了。
        • 这个属性在 Hibernate 中工作(我已经在 Hibernate 4.1 中尝试过):entityManager.getEntityManagerFactory().getProperties().get("hibernate.connection.datasource");
        【解决方案5】:

        在SpringBoot环境中可以使用如下:

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

        【讨论】:

          【解决方案6】:
          DataSource dataSource = (DataSource) 
          em.getEntityManagerFactory().getProperties()
                      .get(org.hibernate.cfg.AvailableSettings.JPA_JTA_DATASOURCE);
          

          您可以使用 hibernate 检索数据源。使用 Hibernate 5.3 测试

          【讨论】:

          • 请编辑您的答案并添加一些上下文来描述您的答案如何解决 OP 的问题。
          【解决方案7】:

          试试这个:

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

          【讨论】:

            【解决方案8】:

            我使用的是 Hibernate 5.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;
            

            【讨论】:

              【解决方案9】:

              这对我有帮助。我使用 HikariCP,但我认为这并不重要。

              基本上需要做的是

              1. 查找服务注册表
              2. 通过org.hibernate.engine.jdbc.connections.spi.ConnectionProvider类获得服务
              3. 将其解包到javax.sql.DataSource

              可以从 EntityManager 中检索服务注册表

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

              或直接来自EntityManagerFactory

              ((SessionFactoryImpl) entityManagerFactory).getServiceRegistry()
              

              【讨论】:

                【解决方案10】:

                我需要这样做才能运行 Flyway 迁移。我无法使用 Augusto 的方法检索 DataSource,但我能够通过从 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");
                

                【讨论】:

                • 不,不。使用不同的DataSource(甚至指向同一个数据库)可能会导致非常微妙的问题。
                猜你喜欢
                • 2011-07-03
                • 2015-12-23
                • 1970-01-01
                • 2022-06-17
                • 2012-08-05
                • 1970-01-01
                • 2012-11-23
                • 1970-01-01
                相关资源
                最近更新 更多