情景
数据库操作时,对数据一致性要求较高的操作应该避免出现如下情况:
如图所示:
若op1与op2同时读取了数据,op1先修改完毕并提交,op2在原数据的基础上修改数据并提交,此时op1的修改即被覆盖,数据处理出现错误。
乐观锁
乐观锁定(optimistic locking)是这样一种技术,它可以确保在实体的状态从数据库中读出来之后,只在没有中间插入的其它事务更改了与这个实体对应的数据库记录的情况下,才把更新后的实体的状态写回数据库。
实现
在表声明中加入@Version
字段作为版本记录字段。如下所示:
@Id
@Column(name = "id")
private int id;
@Version
@Column(name = "version")
private int version;
@Column(name = "col1")
private String col1;
//public getter and setters
/****为防止人为对Version修改,应该把setVersion()改为private***/
验证
写两个方法(伪代码):
@Transactional
public void set1(){
Entity entity = findById(id);
entity.setCol1("1");//此处加断点
em.merge(entity);
}
public void set2(){
Entity entity = findById(id);
entity.setCol1("2");
em.merge(entity);
}
执行流程如下:
1、先执行set1(),并在断点处等待,再执行set2。
2、此时set1(),set2()中的entity的version均为1,数据库中的version也为1。
3、set2执行,由于有@Version
因此update ..... where .... version = 1
,因为version匹配,顺利执行完毕,可以看到数据库中的数据已被更新,此时数据库中version为2。
4、继续set1的更新(merge)时,由于有@Version
因此update ..... where .... version = 1
与数据库的version不匹配,因此报错,抛出异常,事务回滚。