在开发工作中,我们不可避免地会遇到多个任务或应用同时操作同一条数据的情况。在这种情况下,如果不做任何措施,往往会出现数据脏读、脏写等问题,得到的结果不可预知,甚至导致生产事故的出现。因此,我们通常对会出现并发读写的数据上锁来防止这一问题的发生。
以下就是介绍其中的一种锁——乐观锁。
什么是乐观锁
在说明什么是乐观锁之前,需要先说明什么是悲观锁。
其实形象地说,悲观锁就好比去小摊子排队买早餐,只能一人一人按排队顺序购买,后面的人需要等待前面的人买好后才能上前点餐购买,也就是阻塞的。
所以,悲观锁就是认为当一条数据正在被读写时,一定也存在另一处程序或应用想要读写这条数据,所以直接将这条数据锁住,除当前读写者外其它想要读写这条数据的程序或应用都需要等待锁的释放。当这条数据被读写完毕后锁才会被释放。
那么乐观锁说白了就是”锁“写不锁读。这里的锁为什么要加双引号,因为实际上乐观锁并没有强制你不能去写,只是告诉你这条数据在你读取和修改的时间间隙内已经被其它人修改了,如果你觉得有风险那么就放弃这次修改,重新读取后再去修改。也就是乐观锁不强制控制权限,只是把风险告知用户让用户自行决定是否继续修改。
举一个形象的例子,就是去肯德基用手机点餐。假设这一家肯德基只支持手机点餐,那么所有客人在点餐的时候都是一种”读“行为,领餐时就是一种”写“行为(实际上肯德基的点餐逻辑也是如此)。比如点餐时看到的某一菜品还有剩余便点下了,到前台领餐的时候才被告知该菜品当日已售罄,那么此时用户可以选择下次再来或者重新看菜单更换菜品。
这就是一种乐观锁机制,不阻塞,性能也较好,但是对程序的逻辑性要求就会比悲观锁高一些。
乐观锁的实现
下面介绍一种通过表字段来实现乐观锁的方法。
- 创建一张带version字段的表或给原有的表加上version字段
create table op_table (
id varchar(50) primary key,
name varchar(20),
version int
);
alter table src_table add version int;
- 编写sql脚本
这里只给出原始的sql,至于使用什么ORM框架去实现需要根据项目来。
select * from op_table where id = '要修改的数据的id';
update op_table
set name = '乐观锁', version = if(version > 100, 0, version+1)
where id = '要修改的数据的id' and version = n
version = n中的n具体数值为读取到该条数据时候获取的version值