Hibernate: как обеспечить обновление данных с помощью блокировки PESSIMISTIC_WRITE без использования EntityManager.refresh?

1
7

У меня возникла проблема с запросом Hibernate, в котором мне нужно использовать блокировку PESSIMISTIC_WRITE. Блокировка отлично работает в параллельных транзакциях, но информация, возвращаемая запросом, устарела. Чтобы гарантировать актуальность данных, мне нужно вызвать обновление EntityManager, чего я бы предпочел избежать.

Вот code, который я использую:

Я также пробовал использовать некоторые подсказки, такие как:

Однако мне это не удалось. Может ли кто-нибудь мне с этим помочь?

Примечание: я использую Java 8 с базой данных Oracle.

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

public Account findByCodeWithLock(String code) throws Exception {
    TypedQuery<Account> query = em.createQuery("select a from Account a where a.accountCode = :code", Account.class);
    query.setParameter("code", code);
    query.setLockMode(LockModeType.PESSIMISTIC_WRITE);
    logger.info("lock");
    Account account = query.getSingleResult();
    logger.info("getSingleResult: {}", account.getBalanceAmount());
    em.refresh(account);
    logger.info("refresh: {}", account.getBalanceAmount());
    return account;
}
query.setHint("org.hibernate.cacheable", false);
query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH);
query.setHint("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);
Василиса
Вопрос задан6 июня 2024 г.

1 Ответ

2

Hibernate: Обновление данных с помощью блокировки PESSIMISTIC_WRITE без EntityManager.refresh

В Hibernate блокировка PESSIMISTIC_WRITEгарантирует эксклюзивный доступ к данным для текущего сеанса, предотвращая одновременные модификации от других сеансов. Однако она не гарантирует, что данные в сеансе будут синхронизированы с базой данных после изменения. 

1. Использование Session.lock()

Функция Session.lock() позволяет заблокировать объект для изменения, но не обновляет его в базе данных. 

Пример:

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();

// Загрузка объекта из базы данных
MyEntity entity = session.get(MyEntity.class, id);

// Блокировка объекта для обновления
session.lock(entity, LockMode.PESSIMISTIC_WRITE);

// Изменение свойств объекта
entity.setName("New Name");

// Сохранение изменений в базе данных
session.update(entity);

transaction.commit();
session.close();

Объяснение кода:

  • session.lock(entity, LockMode.PESSIMISTIC_WRITE) заблокирует объект  entity для изменения.
  • session.update(entity) сохранит изменения в базе данных.

2. Использование Session.merge()

Функция Session.merge() сливает состояние объекта с состоянием в базе данных. Она также может использоваться для обновления заблокированных данных.

Пример:

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();

// Загрузка объекта из базы данных
MyEntity entity = session.get(MyEntity.class, id);

// Блокировка объекта для обновления
session.lock(entity, LockMode.PESSIMISTIC_WRITE);

// Изменение свойств объекта
entity.setName("New Name");

// Слияние изменений с базой данных
session.merge(entity);

transaction.commit();
session.close();

Объяснение кода:

  • session.merge(entity) обновляет объект entity в базе данных, сливая его с состоянием в базе данных.

3. Использование Session.saveOrUpdate()

Функция Session.saveOrUpdate()сохраняет новый объект или обновляет существующий. Она также может использоваться для обновления заблокированных данных.

Пример:

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();

// Загрузка объекта из базы данных
MyEntity entity = session.get(MyEntity.class, id);

// Блокировка объекта для обновления
session.lock(entity, LockMode.PESSIMISTIC_WRITE);

// Изменение свойств объекта
entity.setName("New Name");

// Сохранение или обновление объекта в базе данных
session.saveOrUpdate(entity);

transaction.commit();
session.close();

Объяснение кода:

  • session.saveOrUpdate(entity) сохраняет или обновляет объект  entity в базе данных.

4. Использование Criteria или  Query с LockOptions

Вы можете использовать  Criteria или Query для загрузки и обновления данных с блокировкой  PESSIMISTIC_WRITE.

Пример:

Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();

// Загрузка объекта из базы данных с помощью Criteria
Criteria criteria = session.createCriteria(MyEntity.class)
  .add(Restrictions.eq("id", id))
  .setLockMode(LockMode.PESSIMISTIC_WRITE);

MyEntity entity = (MyEntity) criteria.uniqueResult();

// Изменение свойств объекта
entity.setName("New Name");

// Обновление объекта в базе данных
session.update(entity);

transaction.commit();
session.close();

Объяснение кода:

  • setLockMode(LockMode.PESSIMISTIC_WRITE)устанавливает режим блокировки для Criteria.

5. Использование @Version аннотации

Аннотация @Version может быть использована для отслеживания версии объекта и автоматического обновления данных в базе данных.

Пример:

@Entity
public class MyEntity {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String name;

  @Version
  private Long version;

  // ...
}

Объяснение кода:

  • @Version указывается для поля  version. Hibernate автоматически обновит значение version при каждом обновлении объекта.

Важно отметить:

  • EntityManager.refresh() не требуется, если вы используете  Session.update()Session.merge(),  Session.saveOrUpdate()или  Criteria /  Query с  LockOptions.
  • Аннотация  @Version предоставляет механизм автоматического обновления данных, но не гарантирует эксклюзивный доступ. 
  • PESSIMISTIC_WRITE - это режим блокировки в Hibernate, который гарантирует эксклюзивный доступ к данным в базе данных.
  • Использование  PESSIMISTIC_WRITE может повысить затраты на производительность, поэтому используйте его только в необходимых случаях.

 

Татьяна
Ответ получен15 сентября 2024 г.

Ваш ответ

Загрузить файл.