MySQL 的锁可以分为三大类
- 全局锁
- 表锁
- 行锁
全局锁
- 对整个数据库实例加锁
- 命令是
Flush tables with read lock (FTWRL)
当你让整个数据库处于只读状态,可以用这个,之后其他线程的所有增删改操作都会被阻塞,包括建表,修改表结构
应用场景
- 典型场景是做全库逻辑备份,确保不会有其他线程操作数据,但是带来的危险就是业务停摆
mysqldump
- 官方自带的
mysqldump
使用参数–single-transaction
时会启动一个事务,这个事务隔离级别为可重复读
,确保拿到了一致性视图,就可以安心备份数据了,也不会影响业务 - 但是数据库引擎必须是
InnoDB
表锁
mysql 表锁有两种
- 表锁
- 元数据锁(meta data lock,MDL)
表锁的语法是
lock tables … read/write
主动释放锁的语法
unlock tables;
对表加读锁后,自己也不能对其进行修改;自己和其他线程只能读取该表。 当对某个表执加上写锁后(lock table t2 write),该线程可以对这个表进行读写,其他线程对该表的读和写都受到阻塞;
行锁
mysql 行锁是由引擎层实现的,并不是所有引擎都支持行锁,MyISAM 不支持行锁
两阶段锁
在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
知道了这个设定,在编写代码中有关于事务的地方,如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。
死锁和死锁检测
当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁。
如我们开启了两个事务,事务A中 update t1 set k=k+1 where id=1
,事务B 中 update t1 set k=k+1 where id=1
。
这时候,事务 A 在等待事务 B 释放 id=2 的行锁,而事务 B 在等待事务 A 释放 id=1 的行锁。 事务 A 和事务 B 在互相等待对方的资源释放,就是进入了死锁状态
两种策略
- 直接进入等待,直到超时,超时时间参数设置为
innodb_lock_wait_timeout
- 发起死锁检测,
innodb_deadlock_detect
设置为on
表示开启检测,发现死锁后,主动回滚某个事务,让另一个事务顺利执行。