问题
- 多个用户或多线程同时查询并更新同一条数据时,后更新的数据会把先更新的数据覆盖掉。
- 比如:有两个用户A和B,同时操作“张三”这条数据,A用户把“张三”改成“李四”,B用户把“张三”改成“王五”;如果在A用户保存之后B用户也点击保存,那么A用户保存的“李四”就会被B用户保存的“王五”覆盖掉,而且A用户和B用户互不知情。
@Version的使用
简介
@Version
是乐观锁,即不对数据库加锁,而是通过保存在数据的版本号来判断数据是否有其他更新,从而保证并发时数据不会被覆盖。
使用代码
- 使用时在数据库表中增加
version
字段,并在实体类中增加@Version
注解,部分代码如下:@Entity @Table(name = "bw_pet") public class Pet{ //id @Column(name = "id") private Long id; @Column(name = "num") private Integer num; @Column(name = "version") @Version private Integer version; //其他代码略... ... }
执行结果
- 增加了
@Version
注解后,在每次更新数据时,数据库中的version
会自增+1,并且在更新时会判断version
是否改变,如果version
改变则说明数据已经有其他更新,不执行本次更新操作并报异常org.springframework.orm.ObjectOptimisticLockingFailureException
。
具体实现过程
- 先看一下没有加
@Version
时,更新num
的sql
语句如下:UPDATE pet SET num = 0 WHERE id = 1;
- 再对比一下增加
@Version
后的sql
语句:UPDATE pet SET num = 0 WHERE id = 1 AND version=2;
- 会发现增加
@Version
后,sql
语句增加了version=2
来判断是否执行更新。 - 如果在
UPDATE pet SET num = 0 WHERE id = 1 AND version=2;
执行前有其他用户先更新了这条数据,那么数据库中的version
会自增为3;这时候如果再执行UPDATE pet SET num = 0 WHERE id = 1 AND version=2;
时,因为语句中的version=2
条件不成立,代码会抛出异常org.springframework.orm.ObjectOptimisticLockingFailureException
,并且不执行sql
语句。