Вопрос о наилучшей практике JPA - обновление только одного поля - PullRequest
2 голосов
/ 10 сентября 2010

Мой вопрос похож на

Обновление одного поля в сущности JPA

В основном у меня есть сущность Foo, которая имеет несколько основных полей (enum, String, DateTime) и имеет два других поля.Один из них - OneToOne, а другой - OneToMany, реализованный с использованием коллекции.

У меня есть два работающих потока, и в разное время я буду искать одну и ту же сущность, используя метод типа findById в классе-оболочке Singleton EntityManager (я этого не писал;)

Что яхотелось бы избежать следующей ситуации:

Поток 1 ищет Foo с идентификатором 1 и получает ссылку на Foo с состоянием Foo на тот момент времени.

Поток 2 ищет Foo с идентификатором 1 и получает ссылку на Foo с тем же состоянием, что и у потока 1

Поток 1 изменяет поле String в Foo и сохраняет его с объединением. Поток 2 изменяетзначение поля Enum для foo и сохраняет его с помощью слияния

Последняя операция приводит к тому, что поток изменений 1 заменяется старым состоянием поля String, полученного потоком 2, поскольку слияние обновляет все (кромеOneToOne и OneToMany, так как их CascadeType является Persist and Remove).

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

Один, хотя у меня был, который я думаю, это то, что упоминается в ссылке в верхней части моего сообщения, должен был изменить вещи, используя общий save(Object o), который он использует сейчас, который выполняет слияние с чем-то специфичным для этого случая, который выполняет ОБНОВЛЕНИЕ для определенного поля, введенного из идентификатора объекта.Есть ли способ лучше?Мой текущий поставщик постоянства - EclipseLink.

TIA

-NBW

Ответы [ 3 ]

3 голосов
/ 13 сентября 2010

Вы должны использовать оптимистическую блокировку (@Version) в JPA.Это приведет к сбою транзакции второго клиента.

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

1 голос
/ 10 октября 2010

Thread1 относится к отдельному экземпляру Foo, и поэтому thread2, ссылающийся на экземпляр diff Foo, оптимистическая блокировка (@Version) не будет работать для вас, поскольку при попытке сохранить отдельный экземпляр во второй раз выдает исключение, лучший способ решить вашу проблему - это делать это каждый раз перед тем, как объединить свою отдельную сущность

Sol1: // загружаем foo каждый раз, когда вы вносите изменения foo = em.find (foodId, Foo.class); //foo.set .. внести изменения em.merge (Foo)

Sol2: // foo ссылается на отдельную сущность em.refresh (Foo); //foo.set .. внести изменения em.merge (Foo)

0 голосов
/ 11 сентября 2010

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

Но я согласен, что в этом случае должно быть что-то более простое.Вы можете использовать простой JDBC и составить запрос на обновление.

...