Создать новую или обновить существующую сущность за один раз с JPA - PullRequest
9 голосов
/ 25 февраля 2010

A имеет объект JPA, который имеет поле метки времени и отличается полем комплексного идентификатора.Мне нужно обновить отметку времени в уже сохраненной сущности, в противном случае создать и сохранить новую сущность с текущей отметкой времени.

Как оказалось, задача не так проста, как кажется на первый взгляд,Проблема состоит в том, что в параллельной среде я получаю неприятное исключение «Уникальный индекс или нарушение первичного ключа».Вот мой код:

// Load existing entity, if any.
Entity e = entityManager.find(Entity.class, id);
if (e == null) {
  // Could not find entity with the specified id in the database, so create new one.
  e = entityManager.merge(new Entity(id));
}
// Set current time...
e.setTimestamp(new Date());
// ...and finally save entity.
entityManager.flush();

Обратите внимание, что в этом примере идентификатор сущности не генерируется при вставке, он известен заранее.

Когда два или более потоков запускают этот блок кодапараллельно они могут одновременно получать null из entityManager.find(Entity.class, id) вызова метода, поэтому они будут пытаться сохранить две или более сущностей одновременно, причем один и тот же идентификатор приведет к ошибке.

Я думаю, что тамЕсть несколько решений этой проблемы.

  1. Конечно, я мог бы синхронизировать этот блок кода с глобальной блокировкой, чтобы предотвратить одновременный доступ к базе данных, но будет ли это наиболее эффективным способом?
  2. Некоторые базы данных поддерживают очень удобный оператор MERGE, который обновляет существующую или создает новую строку, если ее нет.Но я сомневаюсь, что OpenJPA (реализация JPA по моему выбору) поддерживает это.
  3. Если JPA не поддерживает SQL MERGE, я всегда могу вернуться к старому JDBC и делать с базой все, что захочу.Но я не хочу оставлять удобный API и связываться с волосатой комбинацией JDBC + SQL.
  4. Существует волшебная хитрость, чтобы исправить это, используя только стандартный JPA API, но я пока не знаю.

Пожалуйста, помогите.

1 Ответ

1 голос
/ 08 марта 2010

Вы имеете в виду изоляцию транзакций JPA-транзакций. То есть каково поведение транзакций, когда они получают доступ к ресурсам других транзакций.

Согласно этой статье :

READ_COMMITTED - ожидаемый уровень изоляции транзакций по умолчанию для использования [..] EJB3 JPA

Это означает, что - да, у вас будут проблемы с приведенным выше кодом.

Но JPA не поддерживает пользовательские уровни изоляции.

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

...