我需要一种在EJB中动态指定持久性单元的方法。

简化示例:

我有一个使用多个数据库作为数据存储的应用程序。
每个数据存储在结构上都是相同的。
根据连接到应用程序的客户端,我需要从以下位置访问数据
特定的数据存储。

因此,我想使用相同的EJB,以便不重复业务逻辑,
但是只需根据客户端选择正确的持久性单元。

到现在为止,我只用硬编码的持久性单元名称直接注入了实体管理器。
有没有一种方法可以动态地将带有所需的持久性单元的实体管理器注入到EJB?
另外,可以在运行时动态添加持久性单元吗?
我目前必须在persistence.xml文件中指定持久性单元。
理想情况下,我想在系统运行时根据需要在服务器jdbc / db1,jdbc / db2等上创建池。然后只需将它们添加到中央客户端数据库中并将其链接到客户端,以便在客户端连接时,它将检查池的名称,并在调用EJB以获得持久性单元时使用它。

我还是Java EE开发的新手。任何帮助将不胜感激。

最佳答案

不幸的是,在当前的JPA版本中,无法动态创建持久性单元。如果此功能对您很重要,则可以考虑在JPA问题跟踪器中为其创建JIRA问题:http://java.net/jira/browse/JPA_SPEC

使用@PersistenceContext批注,也无法动态选择特定的持久性单元。这实际上是分片的领域,Hibernate曾试图解决这个问题,但随后突然停产。见http://www.hibernate.org/subprojects/shards.html

但是,您可以做一些事情来获得类似的效果。

一种方法是创建一个无状态EJB / CDI工厂bean,并与所有实体管理器一起注入。这样做的成本是微不足道的,因为将这些bean合并在一起,而实体管理器最初创建起来并没有那么昂贵。

如果您还想基于某种条件注入它们,那么该条件将必须在上下文中可用,或者必须在注入点处指定(但是如果您愿意这样做,则可以注入正确的实体管理器直)。

开球示例:

@Stateless
@TransactionAttribute(SUPPORTS)
public class ShardingEntityManagerFactory {

    @Resource
    private SessionContext sessionContext;

    @PersistenceContext(unitName = "pu1")
    private EntityManager entityManager1;

    @PersistenceContext(unitName = "pu2")
    private EntityManager entityManager2;

    @Produces @TransactionScoped @ShardedPersistenceContext
    public EntityManager getEntityManager() {
        if (sessionContext.isCallerInRole("FOO")) {
            return entityManager1;
        } else {
            return entityManager2;
        }
    }
}


然后在您的豆子中:

@Stateless
public class SomeBean {

    @Inject @ShardedPersistenceContext
    private EntityManager entityManager;

    // ...
}


请注意,这里需要作为@TransactionScoped注释。忘记透明地注入实体管理器并注入ShardingEntityManagerFactory并从中手动获取正确的实体管理器也可能会更容易,但更冗长一些。

09-05 16:46