Optimisti c режим блокировки и session.get () против session.createQuery () - PullRequest
1 голос
/ 22 февраля 2020

У меня есть простая сущность с одним атрибутом и версия для оптимизации c режим блокировки.

@Entity
@Table(name = "PERSON")
public class Person implements Serializable {

    @Id
    private Integer id;

    @Version
    @Column(name = "VERSION")
    private Long version;

    @Column(name = "NAME")
    private String name;

}

Я хочу работать с экземпляром в отдельном состоянии.

Шаг 1. Я открываю сессию, как-то загружаю экземпляр, закрываю сессию.

Session session = ... ;
Person person = session.get(Person.class, 1);
session.close();

Шаг 2. Я изменяю значение атрибута person в отдельном состоянии.

person.setName("Bob");

Шаг 3. Я открываю новый сеанс, объедините экземпляр и попросите сеанс вернуть мне экземпляр с помощью метода .get

Session session = ... ;
person = session.merge(person);
// something happen there
// and then we decide to get our instance from session
person = session.get(Person.class, 1); 

System.out.println(person.getVersion()); // result is 0

Шаг 4. Я делаю то же самое, что и на шаге 3, но с запросом.

Session session = ... ;
person = session.merge(person);
// something happen there
// and then we decide to get our instance from session
Query<Person> query = session.createQuery("from Person p where p.id = :id", Person.class);
query.setParameter("id", 1L);
person = query.list().iterator().next();

System.out.println(person.getVersion()); // result is 1

Итак, какая здесь разница? Оба случая затрагивают базу данных, но только второй случай выполняет обновление версии (и это поведение кажется мне неправильным, потому что, если я повторю шаг 4 два раза, я получу исключение DbConcurrentModificationException). Где я что-то пропустил? Где я могу прочитать об этом? Почему версия обновляется не во время гриппа sh?

Hibernate 5.4.12.Final

Спасибо за помощь!

1 Ответ

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

Вы не учитываете очистка .

Очистка - это процесс синхронизации состояния контекста постоянства с базовой базой данных.

6.1 , AUTO flu sh

По умолчанию Hibernate использует режим AUTO flu sh, который вызывает грипп sh в следующих случаях:

  • до совершения транзакция

  • до выполнения запроса JPQL / HQL, который перекрывается с действиями объекта в очереди

  • перед выполнением любого собственного запроса SQL, который не имеет зарегистрированной синхронизации

Итак, при выполнении запроса

Query<Person> query = session.createQuery("from Person p where p.id = :id", Person.class);

Hibernate неявно синхронизирует состояние контекста постоянства с базой данных.

Но когда вы вызываете метод merge, вы должны сделать это самостоятельно.

Session session = sessionFactory.openSession();
Person person = session.get(Person.class, 1L);
session.close();

person.setName("Bob");

Session session2 = sessionFactory.openSession();
Transaction transaction2 = session2.beginTransaction();

person = (Person) session2.merge(person);
session2.flush();

System.out.println(person.getVersion()); // here version will be updated

transaction2.commit();
session2.close();
...