Как программно получить источник данных, используемый модулем персистентности

... без фактического чтения и анализа 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 ответов

Решение

Вам нужно:

  1. бросить EntityManager в EntityManagerImpl (реализация Hibernate)
  2. вызов getFactory()
  3. бросить EntityManagerFactory в HibernateEntityManagerFactory
  4. вызов getSessionFactory() и бросить его SessionFactoryImpl
  5. вызов getConnectionProvider() и приведите его к правильной реализации. Вы можете увидеть реализации здесь. Я предполагаю, что это DatasourceConnectionProvider
  6. вызов 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, но я не думаю, что это имеет значение.

В основном, что нужно сделать, это

  1. найти реестр услуг
  2. получить обслуживание по org.hibernate.engine.jdbc.connections.spi.ConnectionProvider учебный класс
  3. разверните его, чтобы javax.sql.DataSource,

Реестр услуг можно получить из EntityManager

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

или из EntityManagerFactory напрямую

((SessionFactoryImpl) entityManagerFactory).getServiceRegistry()
Другие вопросы по тегам