悲观锁:(pessimistic locking):
假定:发生冲突的概率比较高,
实现:在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)。这样其他事务如果想操作该记录,需要等待锁的释放
特点: 当并发量较大,频繁访问时,等待时间较长,并发访问性不好
例如: java的synchronized,SqlServer页级锁,Oracle行级锁
乐观锁:(optimistic locking)
假设:发生冲突的概率比较低
实现:在提交对记录的更改时才将对象锁住,提交前需要检查数据的完整性
比如,现有两个事务A和B,并且认为A和B是两个原子操作。
A:Cat c = findById(catId);
c.setName("NewCat");
B: update(c)
那么,在B提交前,会锁住c对象(这里代码中并没有锁操作,因为锁操作是B提交前由数据库完成的)。
同时,为了避免A执行后与B执行前之间的这段时间,c对象被其他线程改变了,所以提交前要检查数据的一致性。
检查数据的一致性的方式可以是通过时间戳,或者用自增长的整数表示数据版本号(例如Hibernate、Morphia中的@Version)
如果检查数据已经被改变了,需要回到步骤A重新运行程序,直到提交成功。或者是直接抛出异常,这要看锁的策略了。
由于假定发生冲突的概率比较低的,所以这种重试是可以容忍的,但如果是高并发,就会影响性能了。
这种控制方式也叫乐观并发控制(Optimistic concurrency control)
特点:
读取和改变该对象时不加锁,提交变更前加锁
乐观锁加锁时间要比悲观锁短
可以用较大的锁粒度获得较好的并发访问性能
会增加并发用户读取对象的次数(检查数据一致性时会多一步查询)
时间: 2024-10-09 03:58:45