MySQL锁

MySQL学习总结系列

1.MySQL概览

2.MySQL索引

3.MySQL锁

4.MySQL事务

        锁机制是为了解决数据库的并发控制问题而产生的。如在同一时刻,客户端对同一个表做更新或查询操作,为了保证数据的一致性,必须对并发操作进行控制。同时,在事务特性中,锁机制也为实现 MySQL 的各个隔离级别提供了保证。

锁的分类

        广义上的锁分为乐观锁和悲观锁,它是一种概念不同的软件有各自的实现方式。在MySQL中乐观锁:被访问的数据不会被别人修改,因此先不加锁。如果在操作过程中发现数据被修改,则采用cas重新获取数据进行更新。悲观锁:被访问的数据随时都有可能被修改,因此访问数据之前,先对数据加锁。

        MySQL中根据数据的占用粒度又分为共享锁、排它锁和意向锁。其中共享锁:允许事务读取一行数据,阻止其他事务对数据进行修改。排它锁:允许事务去读取或者修改一行记录,阻止其他事务对数据进行查询或者修改。意向锁:先进行表锁,成功后再进行行锁。意向锁之间相互兼容不会产生阻塞。为了实现表锁和行锁的共存,实现多粒度锁机制。

image-20220303132033771

 不同锁之间的兼容/互斥关系 

        MySQL中根据应用粒度不同还分为行锁、页锁和表锁。其中行锁基于索引实现,其锁定的粒度最小,因此对应的并发也更高,但上锁过程的判断较为复杂,上锁和释放过程都占用较多系统资源,容易产生死锁,代表引擎innodb。表锁与行锁的优缺点基本相反,表锁是针对整个表进行锁定的,其实现简单执行速度快,但由于锁的粒度较大导致并行度较低,代表引擎mylsam。页锁比较少见,顾名思义它是基于数据页进行上锁的,其特性基于上述两者之间,代表引擎BDB。

image-20220303134128774

        从MySQL的实现进行分类锁包括以下几种:

自增长锁:对于自增长id进行插入时如采用表级锁则影响性能;mysql提供了auto_lock_model来处理自增长问题。如果设置为0(插入完成后释放,即便事务未提交也释放锁);1(判断自增长需要使用的数字后立即释放锁,事务回滚会导致不连续),2 直接分配,不使用锁,性能较好,但主键可能不连续。它是一种特殊的表级锁,特定应用在事务插入aotu_increatment类型的列。它能够保障同一个事务插入数据的顺序性;如果是非自增列,则使用插入意向锁(gaplock的一种),在插入位置不冲突的情况下它并不会阻塞彼此。

外键锁:当插入和更新子表时,首先检查父表记录,这可能对数据的检索造成阻塞,不建议增加外键。

Record lock:单条记录上的锁。

Gap lock:间隙锁,锁定一个范围但不包括记录本身。

Nextkey lock:临键锁,record lock+gap lock 锁定一个范围并锁定数据本身。

        间隙锁和临键锁都只在RR事务隔离级别下有效,临键锁能够在可重复读的事务隔离级别下协助解决幻读问题,避免串行化重量级锁对性能的影响。

死锁

        数据库是一个多用户使用的共享资源,当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。当两个事务需要一组有冲突的锁,而不能将事务继续下去的话,就会出现死锁。产生死锁需要满足以下四个条件同时成立:

互斥:至少有一个资源必须处于非共享模式,即一次只有一个进程可使用。如果另一进程申请该资源,那么申请进程应等到该资源释放为止。

占有并等待:—个进程应占有至少一个资源,并等待另一个资源,而该资源为其他进程所占有。

非抢占:资源不能被抢占,即资源只能被进程在完成任务后自愿释放。

循环等待:有一组等待进程 {P0,P1,…,Pn},P0 等待的资源为 P1 占有,P1 等待的资源为 P2 占有,……,Pn-1 等待的资源为 Pn 占有,Pn 等待的资源为 P0 占有。

MySQL中导致死锁的主要有以下情况

1.事务之间对资源访问顺序的交替

        A线程锁定a资源且访问b资源,B线程锁定b资源且访问a资源。两个线程在争用锁的过程中彼此等待导致死锁。

2.并发修改同一个记录

        两个线程并发的修改同一个记录,起先两个线程都获取的是共享锁(读数据),在执行修改时由共享锁升级为排它锁(这个过程需要一定时间),线程A先尝试获取排它锁,发现线程B的共享锁没有释放则进行等待。对于线程B而言也是同样的逻辑,两个线程互相等待导致死锁。(网上的有些说法有问题,其实B线程并没有拿到排它锁,我个人理解这个比较正确)

3.索引使用不当导致的全表扫描

        索引使用不当导致执行了全表扫描,一方面降低了事务的执行速度,使得数据库越来越慢,从时间维度提高了死锁发生的概率;另一个方面将行锁升级为表锁,从锁粒度方面增加了死锁概率。

死锁的避免

        从死锁的必要条件考虑避免死锁的发生

1.尽量避免并发的执行涉及到修改数据的语句。

2.预先规定一个加锁顺序,所有的事务都必须按照这个顺序对数据执行封锁。如不同的过程在事务内部对对象的更新执行顺序应尽量保证一致。

3.尽可能缩短事务的隔离级别、锁粒度、锁持有时间。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值