【问题标题】:Optional persistence unit in JPA (when using multiple persistence units)JPA 中的可选持久性单元(使用多个持久性单元时)
【发布时间】:2013-02-15 19:42:10
【问题描述】:

JPA 是否支持可选的持久性单元,如果支持,我该如何配置?

我确实有一个持久性单元,它是我的主数据库。

然后我配置了另一个,我只是从数据库中读取对象来做一些检查。为了避免搞乱多个数据源上的事务,我设置了第二个数据源jta="false"

但我希望能够检查是否定义了第二个数据源,并且只有在它存在时才使用它。如果未定义,我想简单地跳过我的检查。

问题是我找不到如何使它成为可选的。如果未配置第二个数据源,我会在部署我的战争时从 Jboss 中的部署扫描器中收到 New missing/unsatisfied dependencies 错误:

service jboss.naming.context.java.secondDatasource (missing) dependents: [service jboss.persistenceunit."de.my.war#secondDatasource"] 

(顺便说一句:我使用的是 JBoss 7.1.0 并在 standard.xml 中配置了数据源 - 如果该信息有任何相关性。)

有什么提示吗?

【问题讨论】:

    标签: jakarta-ee jpa java-ee-6 jndi persistence-unit


    【解决方案1】:

    我不确定 XML 配置是否可行,这基本上是在大多数情况下应如何使用 JPA 的约定。尝试寻找一种程序化方法。

    也许您可以通过编程方式将数据源查找为 JNDI 资源,如果找到,您可以自己build an EntityManager。在CDI 的帮助下,它甚至可能没有您想象的那么困难。

    @Produces
    @MyAlterNativeEntityManager
    public EntityManager getEntityManager {
        EntityManager entityManager = null;
        if(jndiLookupMySecondDatasource()){
           entityManager = buildEntityManagerProgrammatically(...);
        }
        return entityManager;
    }
    

    当然,如果未找到数据源,则会返回一个空的 EntityManager,但随后在调用代码中您可以简单地检查它是否已初始化并仅在已初始化时使用。 希望这有助于您走上正确的道路。

    【讨论】:

    • 感谢您的想法。我认为这在处理我的persistence.xml 时已经发生。但我会检查这个......
    • 当然可以,但是这样你甚至不必在persistence.xml中声明第二个数据源!
    • @Balzás Mária Németh:很抱歉我延迟回答这个问题。如果通过 JNDI 找到 datasource,我尝试了您自己构建 EntityManager 的解决方案。但是:我不知道如何在我自己创建的EntityManager 上设置找到的datasourceEntityManagerFactory。它只接受properties 来创建一个。但我手头有一个datasouce。我考虑过自己映射所有必要的属性,但密码是我在datasource 上找不到的。有没有办法让创建的EntityManager 使用我的datasource
    • 我不这么认为。正如 Glen Best 的另一个回答也提到的那样,EMF 必须与一个 PU 相关,因此您无法替换它的数据源,并且没有数据源就没有必要创建一个。如果有数据源,则创建 EMF,如果没有,则无法创建。这个答案对你有用吗?或者我可能误解了这个问题。
    • 我想我可以为第二个datasource 创建第二个EntityManagerFactory。所以这是第二个PersistenceUnit。如果我在persistence.xml 文件中定义它,所有这些都已经有效。唯一的问题是,当第二个 datasource 未定义(在 Jboss 上的 Standalone.xml 文件中)时,我遇到了异常。按照你的想法,我想我可以将第二个 EntityManagerFactory 的创建转移到运行时,这样我就可以避免启动时出现异常。
    【解决方案2】:

    在 JPA 标准中:

    • 每个 EntityManagerFactory (EMF) 必须与一个 PersistentUnit (PU) 相关 - 不可能有多个 PersistenceUnits,也不可能有零个 PersistenceUnits。
    • 每个 EntityManager (EM) 实例都是从 EMF 创建的,因此也有一个 PU。当然,可以从一个 EMF 创建多个 EM,所有这些都使用相同的 PU。
    • 可以使用硬编码配置针对每个 EMF 显式使用的 PU

      EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService");

      或者通过使用注解注入 EMF

      @PersistenceUnit("EmployeeService") EntityManagerFactory 电动势;

      或者可以将其留空,只选择persistence.xml中配置的默认PU。

    • 可以通过使用注解注入 EM 来配置对每个 EM 显式使用的 PU。这里的代码根本没有引用 EMF(让容器不可见地引用 EMF)

      @PersistenceContext(unitName="EmployeeService") EntityManager em;

    在所有这些中,可选 PU 的想法没有任何意义。如果您使用的是 JPA EM,则必须提交到 PU。

    选项:

    1. 编辑 persistence.xml 以在两个不同的物理数据库实例之间具有相同的逻辑持久性单元“切换”。不满足全部要求 - 仍会从替代数据源读取值。
    2. 根据 Balazs Maria Nemeth 的解决方案,查找/注入环境变量(“调试”与否)并以编程方式在不同数据源之间切换。不满足全部要求,因为它仍会从备用数据源读取值。
    3. 查找/注入环境变量(“调试”与否)并适当地为您的替代 EM 运行/排除代码。

    3 是唯一满足全部要求的选项。例如:

    // Inject environment setting. Resource annotation works with/without CDI -  
    // just doesn't give scoping support, which isn't required here.
    @Resource boolean debugMode;
    
    if (debugMode) {
        @PersistenceContext(unitName="DebugPersistenceUnit")
        EntityManager debugEM;
    
        Employee emp = debugEM.find(Employee.class, empId);
    }
    

    然后在您的 web.xml 或 ejb.xml 中包含一个 env-entry:

    <env-entry>
        <description>
         Only set this true in a debugging environment
        </description>
        <env-entry-name>debugMode</env-entry-name>
        <env-entry-type>java.lang.Boolean</env-entry-type>
        <env-entry-value>true</env-entry-value>
    </env-entry>
    

    【讨论】:

      猜你喜欢
      • 2014-06-25
      • 2021-02-17
      • 1970-01-01
      • 1970-01-01
      • 2013-08-18
      • 1970-01-01
      • 2021-04-19
      • 2014-03-28
      • 1970-01-01
      相关资源
      最近更新 更多