对知识补充

数据库--锁

锁可以分为几类

乐观锁和悲观锁

悲观锁对数据的修改抱有悲观态度的并发控制方式。悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。
但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;另外,还会降低并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数据。
乐观锁(Optimistic Locking)是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。对事务而言,检测到冲突后,要么执行回滚,要么重试。

一般使用乐观锁,不会产生死锁现象

排它锁和共享锁

共享锁:线程读加锁数据可读不可写

排它锁:线程读枷锁数据可读可写

表锁和行锁根据粒度来划分


表锁,按照字面意思理解,就是给表加锁。行锁,按照字面意思理解,就是给某一行加上锁,也就是一条记录加上锁。在MySQL中,行锁都是基于索引的,如果一条SQL语句用不到索引是不会使用行级锁的,会使用表级锁。
表锁并发能力很差。行锁粒度变小,并发能力变强,但是相应的锁的开销变大。
表锁和行锁都分为共享锁和排他锁(独占锁),而更新锁是为了解决行锁升级(共享锁升级为独占锁)的死锁问题。
表锁和行锁一起用,所以为了提高效率才会有意向锁(意向共享锁和意向排他锁)。
 

更新锁(避免更新产生死锁)
更新锁在的初始化阶段用来锁定可能要被修改的资源,这可以避免使用共享锁造成的死锁现象。例如,对于以下的update语句:

UPDATE accounts SET balance=900 WHERE id=1
1
更新操作需要分两步:读取accounts表中id为1的记录 –> 执行更新操作。
如果在第一步使用共享锁,再第二步把锁升级为独占锁,就可能出现死锁现象。例如:两个事务都获取了同一数据资源的共享锁,然后都要把锁升级为独占锁,但需要等待另一个事务解除共享锁才能升级为独占锁,这就很造成了死锁(假设还有一份资源,且构成了循环引用)。
更新锁有如下特征:
加锁与解锁:当一个事务执行update语句时,数据库系统会先为事务分配一把更新锁。当执行更新操作时,会把该更新锁升级为独占锁。完成操作后,释放锁。
注意,更新锁与共享锁是兼容的,也就是说,一个资源可以同时放置更新锁和共享锁,但是最多放置一把更新锁。这样,当多个事务更新相同的数据时,只有一个事务能获得更新锁,然后再把更新锁升级为独占锁,其他事务必须等到前一个事务结束后,才能获取得更新锁,这就避免了死锁。同时,更新锁允许多个事务同时读锁定的资源,但不允许其他事务修改它。
 

意向锁:

简单来说,意向锁是表示意图对表中的行添加共享锁或排他锁的表锁。
当表锁和行锁共存时,必须考虑如下情况:事务A锁住了表中的一行,让这一行只能读,不能写。之后,事务B申请整个表的写锁。如果事务B申请成功,那么理论上它就能修改表中的任意一行,这与A持有的行锁是冲突的。数据库需要避免这种冲突,就是说要让B的申请被阻塞,直到A释放了行锁。
数据库要怎么判断这个冲突呢?
step1:判断表是否已被其他事务用表锁锁表
step2:判断表中的每一行是否已被行锁锁住。
注意step2,这样的判断方法效率实在不高,因为需要遍历整个表。于是就有了意向锁。在意向锁存在的情况下,事务A必须先申请表的意向共享锁,成功后再申请一行的行锁。
在意向锁存在的情况下,上面的判断可以改成:
step1:不变
step2:发现表上有意向共享锁,说明表中有些行被共享行锁锁住了,因此,事务B申请表的写锁会被阻塞。
注意:申请意向锁的动作是数据库完成的,就是说,事务A申请一行的行锁的时候,数据库会自动先开始申请表的意向锁,不需要我们程序员使用代码来申请。
 

死锁:

所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁。在数据库里则指事务。
 

死锁条件:

(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

解决死锁:

死锁检测的方法,包括超时死锁检测和等待图死锁判断。
(1) 超时死锁检测
超时死锁检测是最简单的检测方法,如果事务执行超过一定时间,那么就将该事务进行回滚。该方法主要存在的问题是不能便于定义超时时间,也可能造成非死锁的事务回滚。
(2) 等待图死锁检测
有向图
在锁表中,为每一个元素维护了等待X上的锁和X的封锁事务。在等待图中,所有事务是一个结点,对于满足以下要求的事务U和事务T:U持有X上的锁;T等待X上的一个锁;除非U先释放持有X上的锁,否则T不能获得X上的封锁,那么存在 从T到U的弧。
如果等待图中不存在环,那么所有事务最终是能够完成的;但是如果图中有环,那么环中的事务将不能够继续向前,存在死锁。
当一个检测算法判定存在死锁时,系统必须从死锁中恢复。解除死锁最通常的做法是回滚一个或多个事务。需采取的动作有三个:
(1) 选择牺牲者
(2) 回滚
(3) 饿死
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值