0

我将 JavaEE 8 与 OpenLiberty Application server 一起使用。
在我的项目中,我尝试在 CRUD 层中使用 JTA over container managed transaction (BMT)。
这是我的示例代码:

@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?

4

2 回答 2

1

不同之处在于谁管理事务分界

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

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

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

于 2020-12-13T17:43:29.517 回答
1

您在这里提出的问题不是由于容器管理的事务,而是由于 JPA(Java 持久性架构)在乐观插入方面的限制。当您尝试插入一个已经存在的实体时,JavaDoc中的 JPA EntityManager将引发错误(EntityExistsException 或 PersistenceException 以及诸如 SQLIntegrityConstraintViolationException 之类的链式异常)并将事务标记为回滚. 这会阻止您编写将不成功插入异常作为您要提交的有效事务的一部分来捕获的应用程序逻辑。编程模型只是不允许您这样做。无论您是使用容器管理的事务还是应用程序管理的事务,都是无关紧要的。

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

@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-12-14T16:01:56.773 回答