Jakarta ee JPA动态持久化单元名称

Jakarta ee JPA动态持久化单元名称,jakarta-ee,jpa,ejb-3.1,Jakarta Ee,Jpa,Ejb 3.1,我需要一种在EJB中动态指定持久性单元的方法 简化示例: 我有一个使用多个数据库作为数据存储的应用程序。 每个数据存储在结构上都是相同的。 根据连接到应用程序的客户端,我需要从中访问数据 特定的数据存储 因此,我希望使用相同的EJB,以便业务逻辑不会重复, 但是,只需根据客户机选择正确的持久化单元 到目前为止,我只直接向实体管理器注入了硬编码的持久性单元名称。 有没有一种方法可以将所需的持久性单元连接到EJB,动态地注入实体管理器? 另外,可以在运行时动态添加持久性单元吗? 目前,我必须在per

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

简化示例:

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

因此,我希望使用相同的EJB,以便业务逻辑不会重复, 但是,只需根据客户机选择正确的持久化单元

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


我对JavaEE开发还是个新手。任何帮助都将不胜感激。

在当前的JPA版本中,不幸的是不可能动态创建持久性单元。如果这个功能对你很重要,你可以考虑在JPA问题跟踪器上创建一个JRRA问题:

使用
@PersistenceContext
注释,也无法动态选择特定的持久化单元。这实际上是切分的领域,Hibernate曾经试图解决这个问题,但后来突然中断了。看

不过,您可以做一些事情来获得类似的效果

一种方法是创建一个无状态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
注释,这里需要Seam持久性。忘记透明地注入实体管理器,而是注入
ShardingEntityManagerFactory
并手动从中获取正确的实体管理器,这可能更容易,但更详细一些

这可能无助于解决问题,但您可能想知道,JPA2.1的实现正在讨论这类问题

这听起来像是多租户的一种情况:


只是一个想法,不确定是否有用: 您可以打开inputStream来读取
persistence.xml
文件并替换以下行:

<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/agendasccv2?zeroDateTimeBehavior=convertToNull"/>
<property name="javax.persistence.jdbc.password" value="btxbtxbtx"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="root"/>

然后弹出一个用户登录的连接配置屏幕,并根据该文件上的用户权限设置连接,然后启动主应用程序

不确定这是否会有帮助,这只是一个简单的想法。
取决于您的应用程序和业务逻辑。

您可以为此使用相同的持久化单元。当您使用想要使用的url/数据源调用createEntityManagerFactory()时,您只需要提供一个属性映射。

我认为这与多租户确实没有太大的技术距离,但是一个数据库被分成相等的份额,并在多个租户之间共享,这里,单个租户希望多个DBs作为单个DBs出现。@ArjanTijms是正确的。我所寻找的是类似于多租户的,但我不想使用一个数据库,而是想使用更多的数据库。也许值得将每个数据库分离为单独的EJB部署,然后通过web服务连接到。我不喜欢这种开销,但至少它让我可以在需要时自由地跨不同的系统支持数据库。在不同的机器上存储客户端。不确定远程接口是否可以用于此目的?@likoother好主意!是的,向正在运行的系统添加持久性单元的一种动态方法是将EJB模块(EJB JAR)热部署到AS。通过本地接口从技术上“同一个应用程序上的不同应用程序”查找bean并没有指定,但实际上是可行的。您可以使用编程JNDI查找来动态获取封装这些动态添加的持久化单元的bean,而不是直接注入这些bean。虽然这个设置有点不合常规,但它可能会正常工作。@ArjanTijms我怎样才能查找EJB模块的特定部署?我只直接注射过。我读过关于本地和远程接口的书,但据我所知,它们与特定的EJB部署紧密结合。谢谢@ArjanTijms的建议。将尝试JDNI查找部署在服务器上的EJB应用程序。这几乎是我所需要的,但我仍然需要在SharedEntityManagerFactory中预先定义每个持久化单元。我希望能够动态添加它们,这样就不需要更改代码,也不需要重新部署。我可以简单地将持久化单元的详细信息保存在主数据库中,并在需要时将其链接到客户端。但这已经比将每个数据存储实现为单独的web服务要好得多。开销要小得多。web服务还有一个额外的好处,即能够将URL存储在数据库中并动态使用它。我必须增加选项。这主意不错,但在JavaEE环境中不起作用,是吗?您可以注入em工厂,但create方法适用于javase环境