【问题标题】:handle EntityManager dynamically with multiples persistences units使用多个持久性单元动态处理 EntityManager
【发布时间】:2012-11-09 17:28:40
【问题描述】:

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

有问题: 我想根据一些用户条件动态创建一个 EntityManager 函数。

我已经测试了 2 个案例。

第一种情况:基本上,我测试了这段代码(在无状态 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:la transaction est annulée,les commandes sont ignorées jusqu'à la fin du bloc 德拉交易

我认为(在一些 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;
}

没问题,它可以工作,但我必须注入尽可能多的 EntityManagers,我有持久性单元。

  • 如果我有 50 个模式,成本是多少...?
  • 有没有办法真正动态地管理实体管理器? (仅限 1 个 EntityManger)
  • 如果我必须为每个架构创建 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内容更新帖子吗

标签: java jpa entitymanager


【解决方案1】:

通常您没有 50 个架构。我不会担心注入的成本,因为通常 EJB 容器有一个已经打开的连接池,可以随时注入。所以开销真的很小。

AFAIK,JPA 不允许动态实体管理器。

如果您关心资源,我建议您避免使用 EclipseLink(我对 EclipseLink + EJB 的体验非常糟糕)

为了稍微优化一下,我会在这里尝试使用工厂模式。创建一个将为您提供 EntityManagers 的 Bean。而不是注入几个 PersistenceContext 您将使用如下方法进行一次注入:

EntityManager getEntityManager(String schemaId) {...}

另一种选择是将所有注入移至 AbstractBean。所有其他 bean 都继承自 AbstractBean。

【讨论】:

  • 感谢您的建议。目前,这只是一个测试,我想我会将 em 存储在 stafull bean 中,并且由于存储在会话中的属性,用户将获得他们的 em。
  • 我使用 ElcipseLink 因为这是 JPA 的“官方”版本。请问你有什么问题?性能,而不是“用户友好”的使用......?
  • EclipseLink 无法处理遗留数据库的一些复杂关系(我知道 EL 不是这种情况的最佳工具,但仍然如此)。而且在某些查询上速度很慢。我们不得不回退到普通的旧 JDBC。
【解决方案2】:

在使用应用程序管理的持久性单元时,您需要将“eclipselink.target-server”设置为您正在使用的应用程序服务器(有些服务器会自动设置此设置,然后使用容器管理的持久性单元)。然后 EntityManager 将与创建时处于活动状态的 JTA 事务绑定。如果您在 JTA 事务开始之前创建 EntityManager,那么您可以使用 joinTransaction()。

如果您仍有问题,请提供您正在使用的服务器以及完整的异常堆栈跟踪。

如果您有很多架构,您可以考虑使用 EclipseLink 多租户支持,它允许每个租户拥有自己的架构。

http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_multitenant.htm#BABEGBIJ

【讨论】:

  • 非常好!!!我刚刚在我的持久性单元的属性中添加了&lt;property name="eclipselink.target-server" value="SunAS9" /&gt;,因为我使用 Glassfish,现在我可以在运行时动态地实例化 EntityManager。 +1 !
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-17
  • 1970-01-01
  • 2013-02-15
  • 1970-01-01
  • 2015-05-03
  • 2013-09-06
  • 2013-08-18
相关资源
最近更新 更多