悲观锁与乐观锁
悲观锁
顾名思义很悲观,它总假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以在拿数据的时候都会上锁,这样别人想拿这个数据的时候就会阻塞直到它拿到锁为止。在传统关系型数据库就用到了这样的锁机制,比如:行锁,表锁,读锁,写锁等,都是在操作之前上锁。Java中的synchronized关键字也是悲观锁实现的。
乐观锁
顾名思义很乐观,它每次去拿数据的时候都认为别人不会去修改,所以不会上锁,但是在更新的时候会判断在此期间别人是否去更新这个数据,可以使用Version版本号等机制。乐观锁一般多用于读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制就是乐观锁提供。
Version版本号机制
一般在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值就会+1。当线程A更新数据时,在读取数据的同时也会读取version值,在提交更新时,若刚读取到的version值为当前数据库中version值相等时才会更新,否则重试更新操作,直到更新成功。
例子:
假设当前数据库中账户信息表中有version字段,值为1;当前账户余额字段balance,值为100;
首先,A此时读出(version=1),并且账户余额扣除50(100-50)
在A操作的同时B也读入此信息(version=1),并从其账户余额中扣除20(100-20)
A先完成了修改,并将数据版本号+1(version=2),连同账户剩余余额(50)提交至数据库中更新,由于提交版本大于当前版本,数据被更新,version更新为2。
B也完成了修改,将版本号+1(version=2)连同账户剩余余额(80)也一并提交,但此时提交的版本号是2,而数据库中当前版本也是2,所以不满足 ‘提交版本必须大于数据库版本才能执行更新’ 的策略,因此B的提交被驳回。
一般乐观锁用于写比较少的情况下,即冲突很少发生,这样可以省去锁的开销,加大系统的吞吐量。如果经常会发生冲突,这种情况下用悲观锁比较合适。

浙公网安备 33010602011771号