【发布时间】:2012-01-17 05:48:07
【问题描述】:
我有一个附加了 REST Web 服务的 Java EE 应用程序。每个 REST 调用都有自己的无状态 bean 进行操作。这个 bean 调用一个辅助 bean 来创建新项目并将它们持久保存在数据库中。当 REST bean 取回项目时,稍微对其进行操作,然后将其合并到数据库中。这是一般流程
// Bean A
void someRESTCall()
{
Item i = beanB.getItem(...);
// Possible race condition here
if(i == null)
{
i = beanB.buildItem();
if(i == null)
{
// Assume race condition
i = beanB.getItemForce(...); // This has transactional attribute REQUIRES_NEW
}
}
// Do some stuff to the item and merge it
i.setColor("blue");
entityManager.merge(i);
}
// Bean B
Item buildItem(...)
{
Item i = new Item();
i.setName(name); // Name is the primary key, cannot be changed.
try
{
entityManager.persist(i);
}
catch(PersistenceException ex)
{
// Assume threading issue / race condition
i = null;
}
return i;
}
我们最初遇到的问题是,如果两个 rest 调用进入竞争条件,您可能在数据库中有重复项(这会导致约束异常,因为主键不是自动生成的。)
所以,为了解决这个问题,我将返回 null 添加到 buildMachine。问题是事务回滚了,虽然A继续执行,但是回滚后不能正常更新数据库。
所以为了解决这个问题,我尝试在 buildMachine 方法中添加一个 REQUIRES_NEW 事务属性。当我这样做时,当 beanA 去合并它的更改时,我得到一个约束异常。
那么,我怎样才能绕过竞争条件和约束异常呢?也许更重要的是,为什么调用合并会导致约束异常?它应该重用buildItem返回的现有项目数据库行,更改数据库以允许自动生成主键不是一种选择。
有些人建议删除 beanA 中对 entityManager.merge() 的调用,说它是/曾经是多余的。如果我这样做,A 所做的任何更改都不会被合并。
【问题讨论】:
标签: jakarta-ee jboss ejb