【问题标题】:How to handle EntityExistsException properly?如何正确处理 EntityExistsException?
【发布时间】:2010-06-14 13:19:15
【问题描述】:

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

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

但是下面的代码不起作用,因为当EntityExistsException被抛出时,容器将事务标记为仅回滚并尝试返回getFavoritesCounter(question)失败并返回@ 987654325@

@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);
  }

}

问题

@Entity
public class Question implements Serializable {

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

  //getter and setter for id

}

FavoritesCounter

@Entity
public class FavoritesCounter implements Serializable {

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

  @OneToOne
  @Column(unique = true)
  private Question question;

  //getter and setter

}

EntityExistsException 之后返回已创建实体的最佳方式是什么?

【问题讨论】:

    标签: java jpa unique-constraint


    【解决方案1】:

    您可以将 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(),以便容器知道开始新事务。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多