Как сохранить сущности JPA, даже когда метод EJB вызывает исключение? - PullRequest
0 голосов
/ 18 мая 2011

У меня есть EJB, чей метод (среди прочего) сохраняет сущность JPA. Если метод выдает ошибку, транзакция откатывается и сущность не сохраняется.

Однако я делаю хочу, чтобы эта сущность сохранялась независимо от любых исключений, которые могут возникнуть в методе EJB.

Я использую WebSphere 7.0, EJB3.0, JPA 1.0 (OpenJPA в WAS), DB2, если это имеет значение.

Я попытался установить @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) поверх EJB; при этом сущность не сохраняется, даже если нет исключения. Я также попытался зафиксировать транзакцию самостоятельно (em.getTransaction (). Commit ()), но getTransaction () выдает исключение (поскольку транзакции управляются контейнером).

Ответы [ 2 ]

2 голосов
/ 18 мая 2011

Использовать управляемые бином транзакции.

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class MyEJB {
  @PersistenceContext(unitName="...")
  private EntityManager _em;
  @Resource
  private UserTransaction _utx;

  public void myEJBMethod() {
    _utx.begin();
    // Use _em
    _utx.commit();
    // Do other work that might throw an exception.
  }
}

В качестве альтернативы используйте TransactionAttributeType.REQUIRES_NEW, как предложено edalorzo.

1 голос
/ 18 мая 2011

Я не эксперт по EJB, но я уже несколько дней имею дело с JPA и транзакциями.

Недавно я ответил на другой вопрос о том, как объекты находятся в контексте, и как это работает в приложениях Java EE, контекст связан с вашей транзакцией JTA.

Подробности этого ответа можно посмотреть, нажав здесь . Я думаю, что полезно понять, как работает контекст, чтобы понять природу проблем, подобных той, которую вы описываете.

Если вы не предоставляете поддержку транзакций, то нечего сохранять с точки зрения контейнера, и поэтому ваши изменения в контексте являются временными .

Также вы должны учитывать, что, как только возникает исключение, ваш контекст становится недействительным, и сущности в нем отсоединяются. (Есть несколько исключений, например NoResultException).

Таким образом, с этого момента, если вы хотите что-то зафиксировать, вам нужна новая транзакция JTA с новым свежим контекстом JPA, чтобы иметь возможность зафиксировать изменения в базе данных.

Как я уже сказал, я не являюсь экспертом в EJB, но если ваш метод завершится неудачно из-за исключений, и вы все равно хотели бы повторить попытку транзакции, повторно вызвав метод, вы могли бы принудительно создать новую транзакцию каждый раз, когда метод вызывается, и тем самым вы создаете новый свежий контекст JPA.

С другой стороны, если вы хотите, чтобы ваши изменения в сущностях были сохранены, независимо от исключений в методе, то вы можете рассмотреть возможность перемещения кода, обновляющего сущности, в новый метод EJB, определенный для запуска новая транзакция (TransactionAttributeType.REQUIRES_NEW) каждый раз, когда вы ее вызываете.

К тому времени, когда этот второй внутренний метод завершится, ваша работа над транзакциями будет автоматически отправлена ​​в базу данных, независимо от того, какой внешний метод EJB завершился неудачей.

По сути, вы будете предоставлять новый контекст для ваших сущностей и связывать такой контекст с новой транзакцией, которая будет ограничена для фиксации после завершения внутреннего метода.

Насколько я понимаю, естественное поведение в EJB-контейнерах заключается в том, что когда-либо метод присоединяется к уже существующей транзакции, и это то, что вы хотели бы предотвратить, с моей точки зрения.

Другая альтернатива: если вы хотите управлять своим контекстом, используя другую поддержку транзакций, то вы можете рассмотреть возможность предоставления единицы персистентности на основе локальных ресурсов, и вы можете вручную создать экземпляр менеджера сущностей и управлять областью транзакций по своему желанию. Но, честно говоря, для меня это не очень хорошая идея, по крайней мере, в контексте описанной вами проблемы.

...