繁体   English   中英

如何以编程方式将持久化上下文注入到不同的数据源中

[英]How to inject persistence context to different data source programmatically

在标准EJB 3中,当注入实体管理器时,持久性单元(指数据源)被硬编码到注释中:(或者xml文件)

@PersistenceContext(unitName = "myunit")
private EntityManager entityManager;

有没有办法使用实体管理器,但在运行时按名称选择数据源?

使用EclipseLink,您可以设置在应用服务器中配置的DataSource。

import org.eclipse.persistence.config.PersistenceUnitProperties;
...


....
Map props = new HashMap();  
props.put(PersistenceUnitProperties.JTA_DATASOURCE, "dataSource");  
EntityManagerFactory  emf = Persistence.createEntityManagerFactory("UNIT_NAME", props);
EntityManager em = emf.createEntityManager();

PU_NAME引用文件persistence.xml中使用的名称
dataSource将应用程序服务器中用于jdbc资源的名称称为“jdbc / sample”

有可能的! 我已经完成了它,它可以在JBoss AS和WebSphere下运行。

我使用了一个自定义持久性提供程序,它扩展了org.hibernate.ejb.HibernatePersistence (你需要修改一个private static final字段 ,将你的持久化提供程序名称设置为org.hibernate.ejb3.Ejb3Configuration.IMPLEMENTATION_NAME :这是一种黑魔法但是有用)。 确保persistence.xml的持久性单元在<provider>标记中设置了自定义提供程序,并且您的自定义提供程序已在META-INF/services/javax.persistence.spi.PersistenceProvider

我的提供程序覆盖了称为Java EE容器的createContainerEntityManagerFactory(PersistenceUnitInfo,Map)方法(对于JTA数据源,但对于非JTA数据源也很容易):

@Override
public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) {

    // load the DataSource
    String newDataSourceName = ...; // any name you want
    DataSource ds = (DataSource)(new InitialContext().lookup(newDataSourceName));

    // modify the datasource
    try {
        try {
            // JBoss implementation (any maybe other Java EE vendors except IBM WebSphere)
            Method m = info.getClass().getDeclaredMethod("setJtaDataSource", DataSource.class);
            m.setAccessible(true);
            m.invoke(info, ds);

        } catch (NoSuchMethodException e) {
            // method does not exist (WebSphere?) => try the WebSphere way

            // set the datasource name
            Method m = info.getClass().getDeclaredMethod("setJtaDataSource", String.class);
            m.setAccessible(true);
            m.invoke(info, newDataSourceName);

            // do the lookup
            Method m2 = info.getClass().getDeclaredMethod("lookupJtaDataSource", String.class);
            m2.setAccessible(true);
            m2.invoke(info);
        }
    } catch (Throwable e) {
        throw new RuntimeException("could not change DataSource for "+info.getClass().getName());
    }

    // delegate the EMF creation
    return new HibernatePersistence().createContainerEntityManaferFactory(info, map);
}

createEntityManagerFactory(String,Map)也会覆盖但更简单:

@Override
public EntityManagerFactory createEntityManagerFactory(String persistenceUnitInfo, Map map) {

    // change the datasource name
    String newDataSourceName = ...; // any name you want
    if (map==null) map = new HashMap();  
    map.put(HibernatePersistence.JTA_DATASOURCE, newDataSourceName);  

    // delegate the EMF creation
    return new HibernatePersistence().createEntityManaferFactory(persistenceUnitInfo, map);
}

请注意,我这里只写了核心代码。 实际上,我的持久性提供程序还有很多其他功能:

  • 检查DataSource是否已启动并正在运行
  • 为JBoss或WebSphere设置事务管理器
  • 缓存EMF以降低内存使用率
  • 重新配置Hibernate查询计划缓存以减少内存使用量
  • 注册JMX bean(允许多个EAR获得相同的持久性单元名称)
  • 在persistence.xml中配置所需的数据源和持久性单元。
 <persistence-unit name="UNIT_NAME" transaction-type="JTA"> <provider>PERSISTENCE_PROVIDER</provider> <jta-data-source>java:DATA_SOURCE_NAME</jta-data-source> </persistence-unit> -- other units 

现在,在运行时,您可以为所需的持久性单元构建实体管理器。 为每个数据源创建单独的持久性单元。

//---
EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName);
EntityManager em = emf.createEntityManager();
//---
  • 此外,您还可以通过提供db-url,userName等属性的地图来构建工厂。
 createEntityManagerFactory(persistenceUnitName,propertiesMap); 

这将使用给定的属性为命名的持久性单元创建并返回EntityManagerFactory。 因此,您可以相应地在运行时更改属性。

我想说明的用法

Persistence.createEntityManagerFactory(persistenceUnitName)

在Nayan的答案中推荐的按JPA规范(JSR 317)分类如下(“9.2 SE环境中的引导”中的脚注):

“Java EE容器可能支持使用这些Java SE引导API;但是,不需要支持这种使用。”

所以这不是EJB的标准解决方案。 无论如何,我可以确认这在EclipseLink中有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM