JPA EntityManager: merge () пытается создать новую строку в БД - почему? - PullRequest
4 голосов
/ 03 февраля 2011

Я использую JPA через Play Framework.

Я проверяю, кэшируется ли объект User, и если да, то извлекаю его и сливаю () так, чтобы я мог обновить поля исохраните изменения позже:

user = (User) Cache.get("user-auth-" + sessionAuthToken);
if (user != null) {
    user = user.merge();  // I believe this is the same as EntityManager.merge()
}

Однако, когда я делаю это, я получаю следующую ошибку:

PersistenceException occured : 
  org.hibernate.exception.ConstraintViolationException: 
    could not insert: [models.User]
...
Caused by: com.mysql.jdbc.exceptions.jdbc4.
   MySQLIntegrityConstraintViolationException: 
     Duplicate entry '1235411688335416533' for key 'authToken'

Похоже, что он пытается вставить нового пользователя, хотя этот пользователь долженбыть, и уже в базе данных.Почему merge () делает это?

Или, возможно, я поступаю совершенно неправильно - совет будет принят.

Ответы [ 5 ]

3 голосов
/ 04 февраля 2011

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

2 голосов
/ 22 февраля 2011

Я считаю, что ваша проблема в том, как Play управляет средой JPA (и транзакциями).

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

Play облегчает работу с этой моделью двумя способами:

  • Вы должны явно указать, что хотите сохранитьизменение объекта (с помощью save ())
  • Транзакция фиксируется автоматически, если только нет исключения или вы не отметили его для отката (JPA.setRollbackOnly ())

При выполненииСлияние "Вы пытаетесь добавить в диспетчер сущность, которая уже существует, что вызывает исключение уникального ключа.Если вы просто загрузите объект из кэша, вы сможете изменить и вызвать save (), как только это будет сделано, и он будет работать.

1 голос
/ 20 февраля 2013

Это проблема определения сущности ; особенно в отношении первичный ключ / несохраненные значения .

Определение сущности должно быть правильным, чтобы Hibernate распознал его как «уже сохраненный». Например, наличие «нулевого» в поле версии с нулевым значением может привести к тому, что Hibernate проигнорирует любой существующий идентификатор и сочтет его несохраненным.

Это вопрос гибернации, а не только JPA. JPA - это интерфейс - у вас проблемы с конкретной реализацией.

1 голос
/ 03 февраля 2011

Если authToken не является первичным ключом, то, возможно, первичный ключ объединяемого экземпляра User не соответствует первичному ключу его аналога в базе данных, поэтому merge() считает, что это новый User и пытается вставить его.

Итак, проверьте первичный ключ User, возможно, он как-то поврежден или утерян.

1 голос
/ 03 февраля 2011

См. Как правильно повторно прикреплять отдельные объекты в Hibernate? . Merge пытается записать устаревшее состояние в базу данных, чтобы перезаписать возможные другие одновременные обновления. Связанный вопрос упоминает session.lock(entity, LockMode.NONE); как возможное решение, хотя я еще не пробовал.

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