我有一个简单的实体,它有一个属性和乐观锁模式的版本。
@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.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异常(。我在哪里错过了什么?我在哪里可以读到这件事?为什么版本更新不及时?
休眠5.4.12.最终
谢谢你的帮助!
您不考虑冲洗。
Flushing是将持久性上下文的状态与底层数据库同步的过程。
6.1自动冲洗
默认情况下,Hibernate使用AUTO刷新模式,在以下情况下触发刷新:
提交交易之前
在执行与排队实体动作重叠的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();