【数据库】数据库锁机制
一、悲观锁
1、定义:
数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制。
2、分类:
(1)按使用性质分类
共享锁:
事务A对对象T加共享锁,其他事务也只能对T加共享锁,多个事务可以同时读,但不能有写操作,直到A释放共享锁。
特点:多个事务可封锁同一个共享页;任何事务都不能修改该页;该页被读取完毕,共享锁立即被释放。
互斥锁:
事务A对对象T加互斥锁以后,其他事务不能对T加任何锁(即其他事务进入阻塞状态),只有事务A可以读写对象T直到A释放互斥锁。
特点:仅允许一个事务封锁此页;其他任何事务必须等到互斥锁被释放才能对该页进行访问;互斥锁一直到事务结束才能被释放。
更新锁:
更新锁用来预定要对此对象施加互斥锁,它允许其他事务读,但不允许再施加更新锁或互斥锁,当被读取的对象将要被更新时,则升级为互斥锁。
特点:用来预定要对此页施加互斥锁,它允许其他事务读,但不允许再施加更新锁或互斥锁;当被读取的页要被更新时,则升级为互斥锁。更新锁一直到事务结束时才能被释放。
自旋锁:
自旋锁和互斥锁很像,一次只能有一个进程进入临界区,唯一不同的是自旋锁访问加锁资源时,会一直循环的查看是否释放锁。这样要比互斥锁效率高很多,但是仍然需要占用CPU。
特点:自旋锁需要设定一个自旋等待的最大时间,如果持有锁的线程执行的时间超过自旋等待的最大时间扔没有释放锁,就会导致其它争用锁的线程在最大等待时间内还是获取不到锁,这时争用线程会停止自旋进入阻塞状态。除此之外,当自旋锁递归调用的时候会造成死锁现象,所以慎重使用自旋锁。
(2)按作用范围分类(按锁的粒度分类)
行锁:
行锁的作用范围是行级别,数据库能够确定那些行需要锁的情况下使用行锁,如果不知道会影响哪些行的时候就会使用表锁。举个例子,一个用户表user,有主键id和用户生日birthday当你使用update … where id=?这样的语句数据库明确知道会影响哪一行,它就会使用行锁,当你使用update … where birthday=?这样的的语句的时候因为事先不知道会影响哪些行就可能会使用表锁。
表锁:
表锁的作用范围是整张表。
3、优缺点:
优点:悲观锁的优点是能避免冲突的发生。
缺点:悲观锁的缺点是开销较大,而且加锁时间较长,对于并发的访问性支持不好。
二、乐观锁
1、乐观锁的实现
乐观锁的本质不是锁,其隔离级别可以看作为读未提交。乐观锁可以通过以下几种方式实现:版本号/待更新字段
2、优缺点
优点:乐观锁的优点是避免了长事务中的数据库加锁解锁开销,大大提升了大并发量下的系统整体性能表现。
缺点:乐观锁的缺点是只能在提交数据时才发现业务事务将要失败,如果系统的冲突非常的多,而且一旦冲突就要因为重新计算提交而造成较大的代价的话,乐观锁也会带来很大的问题。
三、乐观锁与悲观锁的选择
乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。
悲观锁适用于多写的场景,这种情况下一般会经常产生冲突。