【问题标题】:Combining MDB, JPA and JTA结合 MDB、JPA 和 JTA
【发布时间】:2018-08-02 09:36:55
【问题描述】:

我正在开发一个系统来处理消息并相应地更新数据库,但我需要在层之间保持一定程度的隔离。我想到了以下内容。

  • MyDao.java:提供数据库访问的@Stateless bean。 MyDao 使用 JPA 访问数据库,EntityManager@PersistenceContext 注入。
  • MyMdb.java:侦听队列的 MDB。 MyMdb 通过与@EJB 注入使用MyDao

MyMdb.onMessage() 的一次执行需要对数据库执行多次访问,包括读取和写入。

  • 一方面,这让我认为@Stateless bean 不是MyDao 的正确选择:MyDao 中的EntityManager 实例可以被MyMdb.onMessage() 的不同执行随机访问,导致线程相互干扰。
  • 另一方面,JPA 文档说注入的EntityManager 只是一个代理:它操作的实际持久性上下文 是绑定到 JTA 事务的。这样一切都应该没问题,因为即使 EntityManager 是“共享的”,每个 MDB 也会有不同的事务正在进行,因此可以安全隔离。

什么是正确的场景?我错过了什么吗?

【问题讨论】:

    标签: java jpa jta message-driven-bean


    【解决方案1】:

    以您描述的方式注入无状态 EJB 的实体管理器正是您应该做的。 这种类型的注入提供了一个“容器管理的实体管理器”,它是“事务范围的”。 所以在你描述的场景中。

    1. onMessage MDB 调用将创建一个事务
    2. 对无状态 bean 的调用将发生在相同的事务上下文中,创建一个实体管理器,该管理器将一直持续到事务完成,通常在 MDB 方法返回时。

    用于同一 EJB 实例的特定类型的注入实体管理器无法生存,并且不会在不同事务中重复使用。

    【讨论】:

    • 关于第2点,MyDao是一个无状态会话bean:为什么说它会重新创建呢?由于它是无状态的,容器可以选择MyDao 的任何其他池化实例。这意味着它已经有一个EntityManager 之前被MyMdb另一个 实例注入,把事情搞砸了。我错过了什么吗?
    • 会话 bean 的生命周期有点复杂,无法在此处重现。关键是你看到的是一个线程的代理,它可能被池化或不被池化。至于实体管理器,尽管它可能显示为 bean 的实例,但它的生命周期与事务上下文相关联,这就是为什么称为“事务范围”的原因。总是参考我们的 MDB SLSB EJB 案例。除了扩展的持久性之外,上下文还可以与有状态的 EJB 一起使用,这是另一回事。
    猜你喜欢
    • 2023-03-15
    • 1970-01-01
    • 2011-04-23
    • 2014-12-24
    • 1970-01-01
    • 2012-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多