MySQL基础之全局锁,表锁,行锁


前言

锁是一种数据结构, 被数据库用于处理并发问题.

本文介绍MySQL中的全局锁 , 表锁 , 行锁


提示:以下是本篇文章正文内容,下面案例可供参考

一、全局锁

在做全库逻辑备份的时候,我们需要用到全局锁, 命令为Flush tables with read lockFTWRL命令

使用全局锁做备份时,可能会造成业务停摆,主从延迟等问题, 但是如果不使用全局锁,会造成更严重的后果 :

  1. 如果先对账户余额备份,用户随后做了购买操作,再对发货表进行备份,此时用户余额没变,但是商品已经发货了
  2. 如果将上述操作发过来,用户扣了钱,却没拿到发货

当然,不只是DML增删改,对数据库表字段的更新也会被全局锁限制住

二、表级锁

表级锁分为两种 , 表锁和元数据锁(MDL);

1.表锁

 lock tablesread/write

但是最好不别使用表锁, 锁住整个表的影响面过大, 而innoDB支持行锁, 因此不要使用表锁处理并发

2.元数据锁(MDL)

MDL锁是系统默认在访问表的时候添加上的,无需显示使用; 作用是为了保证读写的正确性

扫描二维码关注公众号,回复: 12856399 查看本文章
  1. 当对某表做增删改查操作时, 自动加上读锁
  2. 当对某表的结构做修改时,自动加上的是写锁

读锁之间并不会互斥,而写锁与读写锁之间会发生互斥. 原因在于对表结构做改动的操作是排队进行进行的(one by one)

在给某一张表做结构修改时,数据库宕机了是什么原因?
原因在于 , 对表结构修改的过程中, 出现了频繁访问数据库的查询操作 , 且客户端又有重试机制 , 数据库的线程被占满了

这就引出来一个问题 , 如何安全地修改表结构? 问题还是在于处理长事务,如果事务不提交,就会一直占用线程且读锁也不会解开
因此可以尝试先杀死长事务 , 再对表结构做修改

三、行锁

当事务A正在对数据库表的某行做更新 , 这时,事务B也对数据库该行进行更新. 此时事务B必须等到事务A提交以后才能再对该行数据进行修改, 这就称为行锁

1.两阶段锁协议

行锁在需要的时候加上,在不需要的时候不会立即释放,而是等到事务结束之后才释放

因此我们需要把最可能造成冲突和影响并发度的锁放在事务的最后

举个例子: 用户购买商品时的操作

  1. 扣除用户账务余额
  2. 增加商家账户余额
  3. 记录日志

由此我们可以推出 , 商家的账户余额操作是最容易产生冲突的. 因为商家与客户是一对多的关系, 对于商家的余额更新操作可能同时有多个事务

此时在事务中,我们应该将操作2放到最后

2.死锁及其检测

当系统中的各个线程都在等待其它线程释放资源时 , 就是我们说的死锁现象

解决方案如下:

  1. 不对线程做操作,直接等待超时 innodb_lock_wait_timeout设置超时时间
  2. 发起死锁检测,系统会主动回滚某一个被死锁了的事务innodb_deadlock_detect默认为on(开启)

我们通常会使用死锁检测的方式 , 但是死锁检测也会带来CPU资源大量消耗的问题

此时的解决方案又有两种

  1. 能断定不会出现死锁检测的事务,直接关闭死锁检测
  2. 在数据库服务端控制并发度(改源码,中间件等)

如果团队技术能力不够, 以上述例子为例 , 我们可以把商家余额的字段划分为10个字段,这样也能减小CPU消耗

猜你喜欢

转载自blog.csdn.net/qq_45596525/article/details/114693055