Как программно получить источник данных, используемый модулем персистентности
... без фактического чтения и анализа persistence.xml
Я могу получить название единицы персистентности EntityManager
используя свойства его фабрики. Я могу получить доступные источники данных, используя jboss-as-controller-client. Но я не нашел API, который дал бы мне источник данных конкретного EntityManager
,
String
с именем будет достаточно.
Спасибо
Я работаю с Hibernate 4.0.1.Final над JPA 2 на JBoss 7.1.1.Final.
РЕДАКТИРОВАТЬ: и я хотел бы избежать перехода от JPA к Hibernate API, если это возможно.
РЕДАКТИРОВАТЬ: решение Аугусто сработало, у меня есть некоторые замечания по деталям: кастинг EM не работал из-за ClassCastException
:(org.jboss.as.jpa.container.TransactionScopedEntityManager cannot be cast to org.hibernate.ejb.EntityManagerImpl
), но это сработало для найденной фабрики. Поэтому я пропустил шаг 1.
Я также не смог найти способ получить имя источника данных из экземпляра. Поэтому мне пришлось довольствоваться названием каталога: connectionProvider.getConnection().getCatalog();
8 ответов
Вам нужно:
- бросить
EntityManager
вEntityManagerImpl
(реализация Hibernate) - вызов
getFactory()
- бросить
EntityManagerFactory
вHibernateEntityManagerFactory
- вызов
getSessionFactory()
и бросить егоSessionFactoryImpl
- вызов
getConnectionProvider()
и приведите его к правильной реализации. Вы можете увидеть реализации здесь. Я предполагаю, что этоDatasourceConnectionProvider
- вызов
getDataSource()
и вы сделали.
К сожалению, вы должны использовать Hibernate API, поскольку нет способа извлечь источник данных с помощью JPA API.
В среде Spring вы можете использовать это:
import org.springframework.orm.jpa.EntityManagerFactoryInfo;
...
@PersistenceContext
EntityManager entityManager;
public DataSource getDataSourceFromHibernateEntityManager() {
EntityManagerFactoryInfo info = (EntityManagerFactoryInfo) entityManager.getEntityManagerFactory();
return info.getDataSource();
}
Я использую 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() этому методу (в моем случае у меня есть несколько фабрик. Затем я могу использовать этот метод для получения источника данных для любого из них при необходимости).
Если вы просто хотите, чтобы имя источника данных и имя источника данных было указано в соответствии со стандартом JPA, вы сможете получить эту информацию с помощью:
entityManager.getEntityManagerFactory().getProperties().get( "javax.persistence.jtaDataSource" );
или же
entityManager.getEntityManagerFactory().getProperties().get( "javax.persistence.nonJtaDataSource" );
в зависимости от того, как вы определили источник данных.
Мне нужно было сделать это для запуска миграций Flyway. Мне не удалось получить источник данных с помощью метода Августо, но я смог воссоздать источник данных, получив URL-адрес, имя пользователя и пароль из свойств SessionFactory:
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");
Попробуй это:
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();
Я использую 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;
В среде 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";
}
DataSource dataSource = (DataSource)
em.getEntityManagerFactory().getProperties()
.get(org.hibernate.cfg.AvailableSettings.JPA_JTA_DATASOURCE);
Вы можете получить хранилище данных с помощью hibernate. Протестировано с Hibernate 5.3
Вот что мне помогло. Я использую HikariCP, но я не думаю, что это имеет значение.
В основном, что нужно сделать, это
- найти реестр услуг
- получить обслуживание по
org.hibernate.engine.jdbc.connections.spi.ConnectionProvider
учебный класс - разверните его, чтобы
javax.sql.DataSource
,
Реестр услуг можно получить из EntityManager
((SessionImpl) em).getFactory().getServiceRegistry()
или из EntityManagerFactory напрямую
((SessionFactoryImpl) entityManagerFactory).getServiceRegistry()