悲观锁
就像名字一样,悲观锁就是对数据的操作保持着悲观的态度,用最保守的方式来保证安全。为了保证数据操作的安全,先把数据锁定起来,成功后再把锁放开。悲观锁的实现,往往要依靠数据库提供的锁机制。基本上悲观锁就是数据库层面上的数据安全操作,最常见的就是利用 for update 。
例如Mysql的行级锁和表级锁
在使用 select…for update 的时候会把数据给锁住 ,但是锁可能是行级锁也可能是表级锁,语句使用不当可能会导致性能的巨大差异。
使用for update , 只有在查询条件准确地查询到具体的主键或者索引信息时(一般就是where 后的条件用= 匹配),才会触发行级锁,否则都是表级锁。
比如:
t_student 表, 字段有自增主键SEQ ,学号ID(有索引),姓名NAME,其他省略
select * from t_student where SEQ = 666 for update;
SEQ为主键,如果有查到数据则可以触发行级锁,没有的话就不会触发锁(但是如果条件是 SEQ >= 666 的话会触发表级锁,因为查询条件不准确)
select * from t_student where ID = 666 for update;
同样ID有索引,情况和主键类似,查到就行级锁,查不到不锁数据。
select * from t_student where NAME = '张三' for update;
这条语句没有指定主键或索引字段,会触发表级锁,所有表数据都会锁住。
乐观锁版本号机制
乐观地认为数据操作不会造成冲突,在更新的时候用版本号来检查数据是否更新冲突
具体的操作一般是给数据库对应的表添加一个版本号字段,如t_student 表 ,添加一个 数字类型的 “version” 字段,每次更新操作如下:
update set NAME='XXX' ... , version = version +1 where version ='传参:期望值,就是你一开始查数据的时候查出的version ' and ...
采用上述语句,在2个用户同时查到相同数据时,他们的版本号version 是相同的,同时更新时,先更新用户语句执行正常,同时修改了version 使其加一,第二个用户在更新时就会报错找不到更新的数据,这时候就让服务器的逻辑去决定是放弃更新还是重新查询版本号的值再重新更新。
乐观锁是在数据库的层次去解决并发更新同一条数据时的操作,压力在数据库这边,在并发量大时,自旋的次数大量增加,而且数据库语句执行的次数也增加,个人建议如果是并发量大的情况下不要使用这样的方式。
可以采用了乐观锁的CAS算法方式,把压力转移到服务器端,具体介绍在我另一篇博客:
JAVA实现乐观锁-CAS算法
版权声明:本文为DGH2430284817原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。