使用多个持久化单元动态处理EntityManager

4

我有一个包含多个模式的数据库,因此我有一个带有多个 <persistence-unit /> 的 persistence.xml 文件(命名为 01、02 等)。

问题: 我想根据某些用户条件动态创建 EntityManager。

我测试了两种情况。

第一种情况:基本上,我在无状态 EJB 中测试了这段代码:

String criteria = "01";     
EntityManagerFactory emf = Persistence.createEntityManagerFactory(criteria);
EntityManager em = emf.createEntityManager();

Joueur joueur = new Joueur(); // Joueur is an Entity
joueur.setPseudo("olivier");

em.persist(joueur);

但我收到了异常:

异常原因:[EclipseLink-4002](Eclipse Persistence Services - 2.3.2.v20111125-r10461):org.eclipse.persistence.exceptions.DatabaseException 内部异常:org.postgresql.util.PSQLException:ERREUR:事务已取消,命令将被忽略直到事务块结束

通过一些Stackoverflow帖子的帮助,我认为我的EntityManager由于没有被容器注入,所以没有与我的事务上下文“链接”。

第二种情况:因此,我使用了注入:

@PersistenceContext(unitName="00")
private EntityManager em00;

@PersistenceContext(unitName="01")
private EntityManager em01;

我的函数中的代码:

String criteria = "01";
EntityManager em = getEm(criteria);
...

并获取 getEm() 方法:

private EntityManager getEm(String criteria){

    if (criteria == "00")
        return em00;
    else if (criteria == "01")
        return em01;

    return null;
}

没问题,这是可以工作的,但我必须注入与持久化单元相同数量的实体管理器。

  • 如果我有50个模式,成本将是多少?
  • 是否有一种真正动态管理实体管理器的方法?(仅限1个实体管理器)
  • 即使我不使用它,如果我必须为每个模式创建1个EntityManager,如何改进我的代码以尽可能地消耗最少的资源?

感谢您的建议和反馈

编辑:

我的配置文件:

Persistence.xml:

<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

    <persistence-unit name="00" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/sim/00</jta-data-source>
        <mapping-file>orm_00_beta.xml</mapping-file>
        <class>com.sim.entities.Joueur</class>      
        <properties>
            <property name="eclipselink.ddl-generation" value="create-tables" />
        </properties>       
    </persistence-unit>

    <persistence-unit name="01" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/sim/01</jta-data-source>
        <mapping-file>orm_01_beta2.xml</mapping-file>
        <class>com.sim.entities.Joueur</class>
        <properties>
            <property name="eclipselink.ddl-generation" value="create-tables" />
        </properties>
    </persistence-unit>

</persistence>

orm_00_beta.xml :

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd"
version="2.0">

<persistence-unit-metadata>
    <persistence-unit-defaults>        
        <schema>beta</schema>
    </persistence-unit-defaults>
</persistence-unit-metadata>   

orm_01_beta2.xml :

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd"
version="2.0">

<persistence-unit-metadata>
    <persistence-unit-defaults>        
        <schema>beta2</schema>
    </persistence-unit-defaults>
</persistence-unit-metadata>   


你能否更新帖子并添加相关的persistence.xml内容? - Nayan Wadekar
2个回答

2
当使用应用程序管理的持久单元(某些服务器在使用容器管理的持久单元时会自动设置此项),您需要将“eclipselink.target-server”设置为您正在使用的应用程序服务器。然后,当EntityManager被创建时,它将与当前活动的JTA事务绑定。如果在JTA事务开始之前创建EntityManager,则可以使用joinTransaction()。
如果您仍然遇到问题,请提供您正在使用的服务器和完整的异常堆栈。
如果您有很多模式,可以考虑使用EclipseLink多租户支持,允许每个租户拥有自己的模式。 http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_multitenant.htm#BABEGBIJ

非常好!我刚刚在持久化单元的属性中添加了<property name="eclipselink.target-server" value="SunAS9" />,因为我使用的是Glassfish,现在我可以在运行时动态实例化EntityManager。+1! - Olivier J.

1
通常情况下,您不会有50个模式。我不会担心注入的成本,因为通常EJB容器具有已经打开并准备好被注入的连接池。因此,开销非常小。
据我所知,JPA不允许动态实体管理器。
如果您关心资源,我建议避免使用EclipseLink(我在使用EclipseLink + EJB时有非常糟糕的经验)。
为了优化一些东西,我会尝试在这里使用工厂模式。创建一个Bean,它将为您提供EntityManagers。与注入多个PersistenceContext不同,您将具有一个注入,并具有以下方法:
EntityManager getEntityManager(String schemaId) {...}

另一个选项是将所有的注入移动到AbstractBean中。所有其他的bean都继承自AbstractBean。

感谢您的建议。目前,这只是一个测试,我认为我将把它们存储在状态化的bean中,用户将通过其会话中存储的属性获取它们。谢谢。 - Olivier J.
我使用 EclipseLink,因为它是 JPA 的“官方”版本。你遇到了什么问题?性能问题?不够“用户友好”? - Olivier J.
EclipseLink 无法处理遗留数据库的某些复杂关系(我知道 EL 不是这种情况下最好的工具,但仍然如此)。而且在某些查询上非常缓慢。我们不得不回退到老旧的 JDBC。 - WeMakeSoftware

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接