MySQL 三种锁


MySQL 三种锁

全局锁

Flush tables with read lock (FTWRL) 对整个数据库加锁,整个库处于只读状态,之后的其他线程例如DML,DDL,TCL等语句将会被阻塞。

全局锁的使用场景是做全库逻辑备份,但让整库处于只读状态,会导致两个问题。

  1. 如果你在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆
  2. 如果你在从库上备份,那么备份期间从库不能执行主库同步过来的 binlog,会导致主从延迟

MySQL官方使用mysql dump -single-transaction,导数据之前会启动一个事务,来确保拿到一致性视图,不支持事务隔离的引擎如MyISAM,只能通过 FTWRL.

全库只读不使用set global readonly=true的原因:

  1. 在有些系统中,readonly 的值会被用来做其他逻辑,比如用来判断一个库是主库还是备库。
  2. 在异常处理机制上有差异。执行 FTWRL 命令之后由于客户端发生异常断开,那么 MySQL 会自动释放这个全局锁,整个库回到可以正常更新的状态。将整个库设置为 readonly 之后,如果客户端发生异常,则数据库就会一直保持 readonly 状态,这样会导致整个库长时间处于不可写状态,风险较高

表级锁

1.表锁

上锁:lock tables ...read/write 解锁:unlock tables。

unlock tables可以主动释放锁,也可以在客户端断开的时候自动释放锁。

lock tables,语法除了会限制线程的读写外,还会限定该线程接下来的操作对象。

2.元数据锁(meta data lock)

不需要显式使用,在访问表时会自动加上,MDL的作用是保证读写的正确性。

当对一张表进行DML操作时会加MDL读锁,对表结构做操作时会加DML写锁。

  1. 读锁之间不互斥,可以多个线程同时对一张表进行增删改查
  2. 读写锁,写锁之间相互互斥,用来保证表结构操作的安全性。

事务中的MDL锁,在语句开始执行时申请,但是语句结束后并不会马上释放,而是等整个事务提交后释放。

如何安全的给小标加字段?

alter table 语句里面设定等待时间,如果在这个指定的等待时间里面能够拿到 MDL 写锁最好,拿不到也不要阻塞后面的业务语句,先放弃。之后开发人员或者 DBA 再通过重试命令重复这个过程。

3.行锁

MySQL行锁在引擎层,由各个引擎自己实现,MyIsAM不支持行锁。行锁就是在表中行记录的锁。

两阶段锁

在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。两阶段锁,锁的添加与释放分到两个阶段进行,之间不允许交叉加锁和释放锁。 也就是在事务开始执行后为涉及到的行按照需要加锁,但执行完不会马上释放,而是在事务结束时再统一释放他们。

如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放

死锁和死锁检测

当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁。

出现死锁后的策略

  1. 直接进入等待,直到超时。这个超时时间可以通过参数 innodb_lock_wait_timeout 来设置。
  2. 发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑。

死锁检测的条件:如果要加锁访问 的行上 有锁,他才要进行死锁检测。

  • 一致性读不会加锁,不会进行死锁检测
  • 并不是每次死锁检测都会扫描所有事务,比如现在有B在等A,D在等C,现在来了一个E,发现E需要等D,那么E就判断跟D、C是否会形成死锁,这个检测不用管B和A

如果是我们上面说到的所有事务都要更新同一行的场景呢?

每个新来的被堵住的线程,都要判断会不会由于自己的加入导致了死锁,这是一个时间复杂度O(n^2)

怎么解决由这种热点行更新导致的性能问题呢

  1. 如果你能确保这个业务一定不会出现死锁,可以临时把死锁检测关掉。风险太高,关掉死锁检测意味着可能会出现大量的超时,这是业务有损的
  2. 控制并发度:在数据库服务器端做并发控制。如果有中间件,可以在中间件实现;如果可以修改MySQL源码,也可以做在MySQL里面,对于相同行的更新,在进入引擎之前排队。这样在 InnoDB 内部就不会有大量的死锁检测工作了。
  3. 从逻辑上将一行拆分为多行,


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM