JPA - только первый коммит потерпел неудачу, но должен провалиться все - PullRequest
4 голосов
/ 04 сентября 2011

пожалуйста, кто-нибудь может мне помочь объяснить следующее (для меня) очень странное поведение JPA.Я намеренно меняю первичный ключ объекта, который запрещен в JPA.

Поэтому при первом правильном коммите выдается «Exception Description: атрибут [date] класса [some.package.Holiday] сопоставлен со столбцом первичного ключа в базе данных. Обновления запрещены.".

Но второй (третий, четвертый, ...) успешен ...!Как это возможно?!

Holiday h1 = EM.find(Holiday.class, new GregorianCalendar(2011, 0, 3).getTime());

try {
    EM.getTransaction().begin();
    h1.setDate(new GregorianCalendar(2011, 0, 4).getTime());
    EM.getTransaction().commit();
    System.out.println("First commit succeed");
} catch (Exception e) {
    System.out.println("First commit failed");
}

try {
    EM.getTransaction().begin();
    EM.getTransaction().commit();
    System.out.println("Second commit succeed");
} catch (Exception e) {
    System.out.println("Second commit failed");
}

Будет распечатано:

First commit failed
Second commit succeed

OMG, как это возможно?!

(Использование EclipseLink 2.2.0.v20110202-r8913 с MySQL.)

1 Ответ

1 голос
/ 05 сентября 2011

Сбой операции фиксации для первой транзакции не имеет отношения ко второй транзакции.Это связано с тем, что при сбое первого коммита EntityTransaction больше не находится в активном состоянии.Когда вы запускаете второй вызов em.getTransaction().begin, инициируется новая транзакция, в которой нет каких-либо сведений о первом .

Важно отметить, что хотя ваш код может использовать тот жеEntityTransaction ссылка в обоих случаях не обязывает этот класс фактически представлять транзакцию.В случае EclipseLink ссылка EntityTransaction фактически оборачивает экземпляр EntityTransactionWrapper, который дополнительно использует RepeatableUnitOfWork, причем последние два класса предоставляются реализацией EclipseLink, а не JPA.Это экземпляр RepeatableWriteUnitOfWork, который фактически отслеживает набор изменений, внесенных в сущности, которые будут объединены в общий кэш (и базу данных).Когда первая транзакция завершается неудачно, базовый UnitOfWork становится недействительным, и при запуске второй EntityTransaction.

устанавливается новый UnitOfWork. То же самое будет применяться к большинству других поставщиков JPA, как и EntityTransactionкласс не конкретный финальный класс.Вместо этого это интерфейс, который обычно реализуется другим классом в поставщике JPA и который также может обернуть транзакцию, требуя, чтобы клиенты использовали ссылку EntityTransaction вместо прямой работы с базовой транзакцией (которая может быть транзакцией JTA).или локальная ресурсная транзакция).

Кроме того, следует помнить, что:

  • EntityTransaction.begin() следует вызывать только один раз.Повторный вызов приведет к возникновению исключения IllegalStateException, так как оно не может быть вызвано, когда транзакция активна.Таким образом, тот факт, что вы можете вызвать его во второй раз, означает, что первая транзакция больше не активна.
  • Если вам требуется, чтобы изменения, выполненные в контексте первой транзакции, были доступны дляво-вторых, вы должны объединить сущности обратно в общий контекст во второй транзакции, после того как они были отсоединены первой.Хотя это может показаться смешным, вы должны помнить, что отдельные объекты могут быть изменены клиентами (чтение, конечные пользователи) до их слияния, поэтому изменения, сделанные конечными пользователями, могут быть сохранены, а ошибки (например, изменение).первичных ключей) могут быть исправлены в промежуточный период.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...