数据库锁机制
对数据库的锁机制做了以下总结:
乐观锁
乐观锁就如同他的名字一样,当其他人(线程)去取数据的时候,总是认为别人不会修改数据,总不会发生并发问题,所以因此没有上锁,只有在线程提交数据时会通过检查版本号的形式检测数据有没有被修改过。一般会在数据表中添加版本号(Version)字段来表示被修改的次数,当数据被修改,version+1,只有在version字段和当前数据库的version值相同时,才提交成功
实现:大多数基于数据版本(Version)记录机制实现
特点:总是假设是最好的情况
悲观锁
悲观锁和乐观锁就是相反的存在,他总是认为别人(别的线程)会对数据进行修改,所以都会加锁(读锁,写锁等等)一次只能允许一个线程对数据进行修改,其他线程会被阻塞挂起, java中的synchronized关键字的实现思想就是悲观锁
实现:大多数情况下依靠数据库的锁机制实现
特点:总是假设是最坏的情况
乐观锁和悲观锁的用处
保证数据安全,处理高并发访问
乐观锁和悲观锁的区别
a. 加锁时机不同:
1.悲观锁,从数据开始修改时就将数据锁住,直到更改完成才释放锁
2.乐观锁,直到数据修改完准备提交时才上锁,完成后释放
b.并发性区别
1.因为悲观锁是在事务执行中加锁,当并发量高时,就有可能会对其他事务进程造成影响,造成其他事务进程执行时间过程,导致事务超时
2.乐观锁是在对数据进行检查时才加锁,锁的时间会少很多,而只有锁住数据的时候会影响其它事务。
3.两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适
排它锁(写锁)
概念:
如果事务T对数据对象A加上写锁,那么只允许事务T读取和修改对象A,其他事务都不能在对A加任何类型的锁,知道事务T释放当前写锁
意义:
保证了事务T在释放在数据对象A的锁前其他事务无法读取和修改数据对象A
共享锁(读锁)
概念:
如果事务T对数据对象A加上读锁,那么其他事务只能再对数据对象A加读锁,而不能加写锁,知道事务T释放在A上的读锁
意义:
保证了其他事务可以读取数据对象A,但是在释放锁之前不能对A进行任何修改
相容矩阵
活锁
如果事务A封锁了数据对象R,事务B请求封锁R,于是事务B就等待事务A释放锁,事务C也请求封锁R,但是事务A在释放在R上的锁后,系统首先批准事务C封锁R,事务B就只能继续等待,紧接着,事务D也请求封锁R,事务C在释放锁后,系统又允许D对R加锁,事务B只能继续等待,这种情况就是活锁,永远的等待下去
解决策略
可以采用类似优先队列的方式去解决,当多个事务请求封锁统一数据对象时,系统根据请求的先后顺序对这些事务排队,当数据对象上的锁一旦释放,就首先批准队列中第一个加锁
死锁
如果两个事物分别锁定了两个单独的对象,这时每一个事务都要求在另一个事务锁定的对象上获得一个锁,因此,每一个事务都必须等待另一个事务释放当前占有的锁
当发生死锁现象时,系统可以自动检测到,然后通过自动取消其中一个事务来结束死锁,根据事务处理时间长短来确定事务的优先级,处理时间长的事务优先级较高,当发生冲突时,保留优先级高的事务,取消优先级低的事务
解决策略
预防死锁就要破坏产生死锁的条件
1.一次封锁法:
一次封锁法要求每个事务都必须一次将所有要使用的数据全部加锁,否则就不能继续执行
缺点:
1.一次就将全部数据加锁,扩大了封锁的范围,降低了系统的并发量
2.数据库中的数据总是不断变化的,很难事先确定每个事务需要加锁的数据对象,只能扩大加锁范围,但是这样会降低并发度
2.顺序封锁法
预先对数据进行规定一个封锁顺序,所有事物按照顺序封锁
缺点:
1.数据对象变化不定,维护成本高
原文链接:https://blog.csdn.net/weixin_41922289/article/details/88882325