2010-09-10 1 views
2

Мой вопрос похож наJPA практика вопроса лучше всего - обновление одного поля только

Updating one field in JPA entity

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

У меня есть две темы, которые работают и в разное время будут смотреть на один и тот же объект, используя метод типа findById на класс обертку Singleton EntityManager (я не пишу;)

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

Тема 1 рассматривает Foo, который имеет идентификатор 1, и он получает ссылку на Foo с состоянием Foo в этот момент времени.

Тема 2 смотрит на Foo, который имеет идентификатор 1 и получает реф к Foo в том же состоянии, как нить 1

Thread 1 изменяет поле Строка на Foo и сохраняется его слияния резьбы 2 изменяет значение поля Enum на foo и сохраняет его с помощью слияния

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

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

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

ТИА

-NBW

+0

Можете ли вы разместить код? –

+0

См. Ответ [здесь] (http://stackoverflow.com/questions/3476613/updating-one-field-in-jpa-entity/18875850#18875850), чтобы увидеть поддержку JPA 2.1 поддержки частичного обновления –

ответ

0

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

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

3

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

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

1

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

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

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

Смежные вопросы