1. 全局锁
对整个数据库加锁
Flush tables with read lock (FTWRL)// 整库只读
数据更新语句(数据的增删改)、数据定义语句(包含建表、批改表构造等)和更新类事务的提交语句都会被阻塞。
全局锁的典型应用场景是,做全库逻辑备份
应用 msqldump 工具并加上–single-transaction 能够开启一个事务, 进行逻辑备份, 数据也是能够失常更新的
set global readonly=true // 全库只读,readonly 个别用来判断主库还是备库, 遇到异样时 FTWRL 会开释全局锁,readonly 遇到异样会始终导致库不可写, 危险较高
2. 表级锁
MySQL 外面表级别的锁有两种:一种是 表锁 ,一种是 元数据锁(meta data lock,MDL)。
表锁:
lock tables ... read/write
unlock tables
如果在某个线程 A 中执行 lock tables t1 read, t2 write; 这个语句,则其余线程写 t1、读写 t2 的语句都会被阻塞。同时,线程 A 在执行 unlock tables 之前,也只能执行读 t1、读写 t2 的操作。连写 t1 都不容许,天然也不能拜访其余表。
MDL 锁
执行增删改查语句 (DML 语句) 时主动会加上 MDL 读锁;
执行表构造更改语句 (DDL) 时主动会加上 MDL 写锁;
session C 在获取 MDL 写锁时会被阻塞,session D 在获取 MDL 读锁时受 session C 的影响也会被阻塞
3. 行锁
innoDB 事务中, 行锁是在须要的时候才加上的, 事务完结时才开释;
假如你负责实现一个电影票在线交易业务,顾客 A 要在影院 B 购买电影票。咱们简化一点,这个业务须要波及到以下操作:
- 从顾客 A 账户余额中扣除电影票价;
- 给影院 B 的账户余额减少这张电影票价;
- 记录一条交易日志。
锁竞争抵触的最大局部在于 2 步骤, 如果把 2 步骤放到最初一行, 则最大限度能够缩小事务之间的锁竞争
死锁
事务 AB 相互期待对方开释资源, 即进入死锁状态, 当呈现死锁当前有两种策略
当进入死锁状态时, 个别有两种策略:
- 间接进入期待, 直到超时, 超时工夫能够通过参数
innodb_lock_wait_timeout
来设置, 默认 50s - 发动死锁检测, 发现死锁后被动回滚其中一个事务,
innodb_deadlock_detect
设置为 on 示意开启
死锁检测时间复杂度为 O(n²), 即 1000 个并发线程更新同一行, 死锁检测操作量级为百万级
优化计划为:
1. 拆行, 一行数据拆多行, 管制并发度
2. 限流, 管制同一时间的线程数
3. 敞开死锁检测, 会呈现大量业务超时
问题
退出要删除 10000 行数据, 有三种形式, 哪种更好?
1.delete from T limit 10000;
2. 在一个连贯中循环执行 20 次 delete from T limit 500;
3. 在 20 个连贯中同时执行 delete from T limit 500;
办法 1: 事务太长, 长事务会造成 redolog 过长, 响应延时会变大; 并且长事务会引起锁竞争, 事务阻塞
办法 2: 绝对较好, 长事务切分为多个短事务, 但会引起数据不统一, 即在两次 delete 中插入新数据, 会被误删, 个别如果是自增主键的话, 能够加上 order by
办法 3: 会产生并发问题, 循环期待造成死锁