Spring / JPA / Hibernate / PostgreSQL генерирует исключение EntityNotFoundException во вложенной транзакции - PullRequest
2 голосов
/ 01 июня 2011

У меня есть следующие настройки: Spring -> JPA -> Hibernate -> PostgreSQL

Я создал сервисный слой, который предлагает несколько методов "@Transactional" для вставки данных. В конкретном случае данные - это объект лица, который должен быть связан с объектом категории (идентифицирующее отношение) и некоторыми объектами изображения (не идентифицирующее отношение).

Поскольку я должен предложить импортер, я создал метод (также @Transactional) для импорта файла CSV. Этот метод сначала пытается вставить категории (что хорошо работает с помощью em.persist (), который используется из DAO, вызываемой сервисным уровнем). Затем я добавляю нового человека, который становится связанным с категорией, которую я добавил ранее (категория загружается, как если бы она уже была в базе данных -> запрос HQL), которая также работает, поскольку категория сохраняется в выполняющейся транзакции. Сущность person также использует em.persist () для сохранения в транзакции.

Теперь я создаю изображения сущностей и подключаю их к сущности человека. После их подключения я также сохраняю человека, но, поскольку он уже сохранен в транзакции, я использую em.merge (). Здесь я получаю «EntityNotFoundException ()», так как hibernate (или jpa) не может загрузить категорию с первого шага (у нее правильный идентификатор, но, похоже, он не видит транзакцию) ...

Все три метода insertCategory (), insertPerson () и addPicture () также объявлены как @Transaction, так как они используются отдельно в обычном случае использования. Возможно, проблема связана с вложенной транзакцией, но, скорее, она связана с em.merge (), так как em.persist () работает хорошо.

em - это EntityManager, который добавляется весной.

Есть идеи, что не так?

Привет Бен

1 Ответ

1 голос
/ 01 июня 2011

Если вы используете прокси (Spring по умолчанию для обработки транзакций), аннотация @Transactional игнорируется при вызове методов в классе. Следующее не будет работать:

@Transactional
public void doStuff() {
  this.doSomeOtherStuff();
}

@Transactional(propagation=Propagation.REQUIRES_NEW)
public void doSomeOtherStuff() {
  // do some more db work here.
}

Если вы действительно делаете это, у вас есть два варианта:

  1. Используйте AspectJ вместо прокси. Это требует немного обучения.
  2. Перемещение методов, требующих транзакций, в другой класс.

Подробнее об этом можно прочитать в документации Spring здесь .

В режиме прокси (который используется по умолчанию) перехватываются только внешние вызовы методов, поступающие через прокси. Это означает, что самовывоз, по сути, метод в целевом объекте, вызывающий другой метод целевого объекта, не приведет к фактической транзакции во время выполнения, даже если вызванный метод помечен @ Transactional.

...