乐观锁和悲观锁
0.锁
并行会导致冲突,冲突需要解决,于是就有了锁。
1.悲观锁
悲观锁,pessimistic lock,每次拿数据的时候都认为别人会修改,所以在每次拿数据的时候都会上锁,这样别人想拿这个数据就会block,直到它拿到锁。传统的关系数据库里用到了很多这种锁的机制。
意如其名,悲观锁具有强烈的独占和排他特性。悲观锁的实现,往往依靠数据库提供的锁机制,同时,也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,及时在本系统中实现了加锁机制,也无法保证外部系统不会修改数据。
下面是一个典型的依赖数据库的悲观锁调用:
1 select * from account where name="Erica" for update
这条sql锁定了account表中所有符合where条件的记录,在本次事务提交之前,外界无法修改这些记录。
2.乐观锁
乐观锁,optimistic lock,每次拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
乐观锁的实现是在数据库表加上version版本号的字段,每次修改数据都对version+1,当两个更改请求同时到达数据库,A取到version=1,然后对数据进行修改,修改后将version+1=2写入数据库,此时数据库里的version=1,写入的version大于数据库里的version,乐观锁就认为可以写入,数据库的version被更新为2,; 此时B取到的version也是1,然后对数据修改,修改后version+1=2写入数据库,写入时和数据库的version比对,发现version=2,没有大于数据库中现存的版本号,于是拒绝写入。
乐观锁一般是在应用层实现,在数据库层的代码如下:
<update id="updateQuestionLevel">
UPDATE activity_question
SET z_index=#{status},
version=version+1
WHERE id=#{questionId}
AND version=#{version}
</update>
3.何时使用
乐观锁适用于多读的应用类型,可以提高吞吐量,
乐观锁适用于写比较少的情况,这样可以省去锁的开销,加大系统的吞吐量。
但是如果经常产生冲突,上层应用就会不断地重试,这样就降低了性能,这种情况下悲观锁就比较合适。