暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL里有哪些锁?

dejavuyj 2021-05-18
235

按锁的粒度划分,MySQL里的锁大致可以分为三类:

  • 全局锁

  • 表级锁

  • 行级锁



全局锁

MySQL提供了Flush tables with read locks的命令,来加全局读锁.让整个数据库处于只读状态,此时不允许进行插入,更新,删除和新增/变更表结构的DDL操作.

全局锁的典型应用场景是用于做全库逻辑备份.特别是在存储引擎不支持一致性读的情况下.

当然如果是支持一致性读的InnoDB引擎,使用MySQL自带的mysqldump工具,并加上-single-transaction参数,导数据之前会启动一个事务,拿到一致性视图.这样在MVCC的支持下,导数据的过程中是可以正常进行更新数据操作的.


表级锁

MySQL里有两种表级锁:表锁和元数据锁(Meta data lock, MDL).

表锁的语法: lock tables read/write. 可以使用unlock tables释放锁,也可以在客户端断开连接的时候自动释放锁.

当一个线程执行lock tables t1 read, t2 write;这个线程在执行unlock tables之前只能读t1表,读写t2表,不能写t1表.并且不能访问其他表.而其他线程写t1表,读写t2表的语句都会被阻塞.

常用的InnoDB引擎默认支持行级锁,因此一般不使用lock tables来做并发控制.毕竟锁的粒度越大,并发度越低.


元数据锁MDL不需要显式使用,做增删改查操作的时候加MDL读锁,对表结构做变更的时候加MDL写锁.

读锁之间不互斥,因此可以增删改查可以并发执行.

读写锁之间互斥,写锁之间互斥,两个线程不能同时对一个表做变更表结构的操作.变更表结构的时候,也不允许增删改查操作.


行级锁

MyISAM引擎不支持行锁.InnoDB支持行锁.

在InnoDB的事务中,行锁是在需要的时候加锁,但是在事务结束时才释放锁.因此应该把最可能造成锁冲突的锁尽量往后放.


MySQL的死锁和java类似,都属于活性失败.双方各自持有对方想要获取的锁.

处理死锁的两种策略:

  • 进入等待,直到超时,超时时间通过innodb_lock_wait_timeout参数来设置,默认值是50

  • 发起死锁检测,发现死锁后,回滚死锁链条中的某一个事务,让其他事务得以继续执行.innodb_deadlock_detect默认值是on.


解决更新热点行的性能问题:

  • 关掉死锁检测,有一定的风险,会造成死锁.

  • 控制并发度,这个并发控制要做在数据库服务端或中间件(因为客户端的数量的数量可能会很多).

  • 将一行改成逻辑上的多行,需要根据业务逻辑做详细设计.


InnoDB中行锁的三种方式:

  1. 记录锁 针对单行记录的锁

  2. 间隙锁 锁住一个范围,但不包括记录本身,可以用来解决幻读问题

  3. Next-key锁 相当于间隙锁+记录锁


间隙锁本身比较复杂,后续可以专门写一篇文章来介绍.


共享锁/排它锁

共享锁 (S锁 ) select * from table where ... lock in share mode;其他线程可以进行查询, 也可以对该记录加共享锁.

排它锁 (X锁) select * from table where ... for update; 其他线程可以进行查询,但是加共享锁或排它锁会被阻塞.

值得一提的是,当查询加上共享锁或排它锁的时候,查到的是最新版本的数据,也就是当前读.

参考文献

极客时间专栏 - MySQL实战45讲

文章转载自dejavuyj,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论