Похоже, что большинство примеров классов объектных компонентов JPA / Hibernate, которые я видел, не выполняют явной синхронизации. Тем не менее, можно вызывать геттеры / сеттеры для этих объектов в контексте создания транзакции. И эти методы можно вызывать в нескольких потоках (хотя, может быть, это необычно и странно).
Похоже, что если он создается в нескольких потоках, изменения в состоянии объекта могут быть потеряны, что было бы печально.
Итак, не учитывает ли лучшая практика синхронизации? Обеспечивает ли инструментальный код Hibernate правильную синхронизацию для меня?
Например:
@Entity
public class Ninja {
@Id @GeneratedValue
private Long id;
@Column
private String name;
@Column
private int throwingStars;
public Ninja() {}
public int getThrowingStars() { return throwingStars; }
public void addThrowingStar() { throwingStars += 1; }
}
Нужна ли синхронизация методов метания звезды? Я точно не хочу, чтобы мой ниндзя терял метательные звезды.




«И эти методы можно вызывать в нескольких потоках (хотя, может быть, это необычно и странно)».
Я могу говорить ТОЛЬКО о спящем режиме, поскольку у меня нет большого опыта работы с JPA. Объект, для которого вы вызываете set, НЕ всегда является тем же самым объектом, для которого вы вызываете get. Когда Hibernate загружает для вас объект, он вызывает методы set *, а затем вы (и ваши потоки) вызываете остальное время.
Опять же, когда вы (то есть ваши потоки записи) изменяете существующий объект, а затем снова сохраняете его, вам необходимо защитить доступ к объекту (чтобы другие потоки чтения / записи не читали грязные данные).
Итак, вы ожидаете увидеть синхронизацию в классе сущности в более позднем случае? Или вы ожидаете увидеть синхронизацию на более высоком уровне, координируемом приложением?
Вероятно, объект для двух потоков не совпадает. Предположим, что ваши потоки используют фабрику сеанса для доступа к базе данных, объекты, которые вы получаете из сеанса, должны рассматриваться как «независимые» (я считаю, что спящий режим создает «свежие» объекты для каждого get (), если они не находятся в сеансе).
Что касается вашего вопроса о звездах, это то же самое, когда два человека извлекают одну и ту же строку из БД, свойства DB 'ACID' будут гарантировать, что каждая операция является атомарной, поэтому, если вы удалите звезду из ниндзя в Thread t1 и совершить, Поток t2 будет читать зафиксированные значения t1.
В качестве альтернативы вы можете попросить спящий режим заблокировать строку соответствующего ниндзя в T1, так что даже если T2 запрашивает строку, ему придется ждать, пока T1 не зафиксируется или не прервется.
Сущности JPA / Hibernate - это объекты POJO. Hibernate и любой другой JPA-провайдер не изменяют сематику времени выполнения.
Так что, если у вас возникнут проблемы с параллелизмом с простым POJO, они также будут у вас с вашей сущностью!
Во всех системах, которые я видел, модель предметной области не является потоковой, экземпляры сущностей не доступны для нескольких потоков.
Однако вы можете одновременно иметь несколько экземпляров одних и тех же объектов. В этом случае синхронизация выполняется по БД. Здесь используются модели оптимистической и пессимистической блокировки. Hibernate и JPA могут помочь вам в реализации этих шаблонов.
Лучшим способом решения вашей проблемы является оптимистическая блокировка:
Из спецификации Java Persistence API (JPA) (глава 3.4.1):
Optimistic locking is a technique that is used to insure that updates to the database data corresponding to the state of an entity are made only when no intervening transaction has updated that data for the entity state since the entity state was read. This insures that updates or deletes to that data are consistent with the current state of the database and that intervening updates are not lost.
Вам нужно добавить аннотацию @Version к вашему классу и столбец в таблице БД.
На мой взгляд, НИКОГДА не следует делить объекты домена между потоками. Фактически, я обычно очень мало делюсь между потоками, поскольку такие данные должны быть защищены. Я построил несколько больших / высокопроизводительных систем, и мне никогда не приходилось нарушать это правило. Если вам нужно распараллелить работу, делайте это, но НЕ путем совместного использования экземпляров объектов домена. Каждый поток должен читать данные из базы данных, работать с ними, изменяя / создавая объекты, а затем фиксировать / откатывать транзакцию. Вход / выход работы обычно должны быть объектами value / readonly.
«[...] изменения состояния объекта должны быть потеряны, что было бы печально». <- Мне нравится это преуменьшение («было бы грустно») :-)