如何正确处理EntityExistsException?

时间:2010-06-14 13:19:16

标签: java jpa unique-constraint

我有两个实体:Question和FavoritesCounter。首次将问题添加到收藏夹时,应创建FavoritesCounter。

考虑两个用户同时向收藏夹添加问题时的用例 - 当第二个用户调用EntityExistsException时,这将导致entityManager.persist(counter)

下面的代码不起作用,因为当抛出EntityExistsException时,容器会将事务标记为仅回滚并尝试返回{{1} } getFavoritesCounter(question)

失败
javax.resource.ResourceException: Transaction is not active

问题

@Stateless
public class FavoritesServiceBean implements FavoritesService {

  ...

  public void addToFavorites(Question question) {
    FavoritesCounter counter = getCounter(question);
    if (counter == null) {
      counter = createCounter(question);
    }
    //increase counter
  }

  private FavoritesCounter createCounter(Question question) {
    try {
      FavoritesCounter counter = new FavoritesCounter();
      counter.setQuestion(question);
      entityManager.persist(counter);
      entityManager.flush();
      return counter;
    } catch (EntityExistsException e) {
      return getFavoritesCounter(question);
    }
  }

  private FavoritesCounter getFavoritesCounter(Question question) {
    Query counterQuery = entityManager.createQery("SELECT counter FROM FavoritesCounter counter WHERE counter.question = :question");
    counterQuery.setParameter("question", question);
    List<FavoritesCounter> result = counterQuery.getResultList();
    if (result.isEmpty()) return null;
    return result.get(0);
  }

}

FavoritesCounter

@Entity
public class Question implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  //getter and setter for id

}

@Entity public class FavoritesCounter implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @OneToOne @Column(unique = true) private Question question; //getter and setter } 之后返回已创建的实体的最佳方法是什么?

1 个答案:

答案 0 :(得分:2)

您可以将createCounter()移动到另一个会话Bean,并使用@TransactionAttribute(REQUIRES_NEW)

标记该方法

或者,您可以将createCounter()移动到FavoritesServiceBean的本地接口(同时确保添加@TransactionAttribute(REQUIRES_NEW)注释)并按如下方式调用它:

@Stateless
public class FavoritesServiceBean implements FavoritesService 
{

    ...
    @Resource
    protected SessionContext sessionContext;

    public void addToFavorites(Question question) 
    {
        FavoritesCounter counter = getCounter(question);
        if (counter == null) {
          counter = sessionContext.getBusinessObject(FavoritesService.class)
                                  .createCounter(question);
        }
       //increase counter
    }

    @TransactionAttribute(REQUIRES_NEW)
    public FavoritesCounter createCounter(Question question) 
    {
        ...
    }
    ...
}

您需要通过业务/本地接口而不是直接调用createCounter(),以便容器知道启动新事务。