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