【问题标题】:What is JTA with container managed transaction advantage什么是具有容器管理事务优势的 JTA
【发布时间】:2020-12-11 19:36:31
【问题描述】:

我将 JavaEE 8 与 OpenLiberty 应用程序服务器一起使用。
在我的项目中,我尝试在 CRUD 层中通过容器管理事务 (BMT) 使用 JTA。
这是我的示例代码:

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class SampleCRUD {

    @Inject
    private Logger logger;

    @PersistenceContext
    private EntityManager em;

    public void insertFood(Food food) {
        em.persist(food);
    }

    public void updateFood(Food food) {
        em.merge(food);
    }

    public Food selectFood(long id) {
        return em.find(Food.class, id);
    }

    public void deleteFood(long id) {
        em.remove(select(id));
    }
}      

和食品实体:

@Table
@Entity
@SequenceGenerator(name = "default_seq", sequenceName = "food_seq", allocationSize = 1)
public class Food extends BaseEntity {

    @Column(unique = true)
    private String name;
    

我想了解:
在 sql 插入/删除/更新操作之前,有什么建议在数据库上选择吗?
我问这个问题是因为在 CMT 模式下无法捕获应用程序上的约束或 SQL 异常。

在我的示例代码中:

  • 需要在持久化之前选择,因为重复键异常会导致应用程序服务器。
  • 需要在删除之前选择,因为在应用程序服务器中找不到实体异常。

什么是具有容器管理事务 (CMT) 优势的 JTA?

【问题讨论】:

    标签: jakarta-ee jta bean-managed-transactions


    【解决方案1】:

    区别在于谁管理事务分界

    如果你自己管理它(BEAN),你可以控制好的和错误的情况(你必须做一个提交/回滚)

    如果你让它做容器,任何未处理的异常都会隐式地导致回滚,并且为你确保提交。 所以你只需要实现逻辑,其余的由JTA完成

    因此,如果您不需要对事务进行任何特殊处理,最简单的方法是将事务处理留给容器

    【讨论】:

      【解决方案2】:

      您在此处提出的问题与其说是由于容器管理的事务,不如说是由于 JPA(Java 持久性架构)在乐观插入方面的限制。当您尝试插入一个已经存在的实体时,JPA EntityManager per the JavaDoc 将引发错误(EntityExistsException 或 PersistenceException 与链式异常,例如 SQLIntegrityConstraintViolationException)和mark the transaction to be rolled back。这会阻止您编写将不成功插入异常作为您要提交的有效事务的一部分捕获的应用程序逻辑。编程模型只是不允许您这样做。无论您是使用容器管理的事务还是应用程序管理的事务都无关紧要。

      根据您的业务逻辑,可以通过强制某些操作在新事务中运行来部分解决该问题,在这种情况下,如果它回滚,调用者的事务不会受到影响。如下所示,

      @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
      public boolean insertFood(Food food) {
          try {
              em.persist(food);
              em.flush();
              return true;
          } catch (PersistenceException x) {
              if (x instanceof EntityExistsException
               || x.getCause() instanceof SQLIntegrityConstraintViolationException)
                  return false;
              throw x;
          }
      }
      

      明显的缺点是该操作不再是调用者事务的一部分。

      您提到了在尝试插入之前运行选择/查找的可能性。这里的问题是当多个线程重叠并且在数据库中都看不到任何东西然后都尝试插入时。该错误仍然会发生,尽管频率较低。悲观锁可能会有所帮助。

      如果数据库/JDBC 驱动程序允许(在插入失败时不会强制回滚),另一种选择可能是放弃使用 JPA 并直接通过 JDBC 将 SQL 命令运行到数据库。

      【讨论】:

        猜你喜欢
        • 2020-09-20
        • 1970-01-01
        • 1970-01-01
        • 2017-02-05
        • 2020-12-07
        • 2013-09-24
        • 2011-12-10
        • 2016-10-30
        • 1970-01-01
        相关资源
        最近更新 更多