Как правильно обрабатывать EntityExistsException? - PullRequest
2 голосов
/ 14 июня 2010

У меня есть две сущности: Question и FavoritesCounter.FavoritesCounter должен быть создан, когда вопрос добавляется в избранное в первый раз.

Рассмотрим вариант использования, когда два пользователя пытаются добавить вопрос в избранное одновременно - это вызовет EntityExistsException, когда для второго пользователя вызывается entityManager.persist(counter).

Но код ниже не работает , потому что при выдаче EntityExistsException контейнер помечает транзакцию как только откат , и попытка возврата 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);
  }

}

Вопрос

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

1 Ответ

2 голосов
/ 14 июня 2010

Вы можете переместить createCounter () к другому сессионному компоненту и пометить этот метод с помощью @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 (), чтобы контейнер знал, что нужно начинать новую транзакцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...