mysql锁分类
参考链接
解决问题
通过锁机制来实现数据的并发访问控制,从而报保证数据的一致性。
实现机制划分
乐观锁和悲观锁其实一致实现锁的一种思想机制。
乐观锁
认为数据在一般情况下,并不会发生并发操作,导致数据冲突,不用每次都加锁(不采用数据自身的锁机制),而是通过程序来实现。比如,版本号和时间戳的方法。
悲观锁
认为每次的操作,都会有并发操作,导致数据产生不一致,持有悲观的状态,所以每次在进行操作是,都会先去获取锁,在对数据操作。
共享锁和排它锁是 悲观锁的不同实现。它们都属于悲观锁的范畴。
锁的粒度划分
全局锁,表级锁,行级锁,页级锁。
全局锁
全局锁就是对整个数据库实例加锁,整个库处于只读状态,DML和DDL的操作将会别阻塞。
- 使用场景
做全库逻辑备份(备份一致性)
- 使用方法
(FTWRL),当你需要让整个库处于可读状态可以使用这个命令
flush tables with read lock;
- 实现全库逻辑备份的方式:
方式一:
对不支持事务的 myisam引擎,就只能使用 FBWRL
方式二:
支持事务的 innodb引擎,则可以使用 mysqldump single-trancaction=可重复读,导出数据之前会启动一个事务,来确保拿到一致性视图,数据是可以正常更新的,mvcc支持
- 全库只读实现方式(不推荐使用)
show variables like "%read%";
通过设置 set globel read_only=true
,方式来设置全库只读
原因:
0、可能在某些情况下,read_only的会用做其他逻辑的判断,比如判断,该库是否主库还是从库
0、在异常处理机制上有差异,FTWRL 命令执行后,如果客户端发生异常断开了,则Mysql会自动释放这个全局锁,
如果使用 read_only,客户端发生异常,则客户端会一致保持这个状态,这样会导致整个库处于不可写状态,非常危险。
表级锁
表级锁:表锁和 元数据锁,意向锁,自增锁
表锁
对整张表加 读锁(共享锁) 或者 写锁(排他锁)。
UNLOCK TABLES释放被当前会话持有的任何锁
- 表锁语法:
-- 加锁
lock tables xxx read/write , xxx read/write
-- 解锁
ulock tables(释放当前会话的所有锁)
- 特点
0、开销小,加锁快
0、锁的力度大,锁冲突的概率最高,支持并发度低,
0、不会查询死锁(会话断开,或者超时会自动释放锁的)
0、表级锁主要是 myisam,memroy,csv等一些分事务性存储引擎使用。
0、在当前会话中锁定了一个表后,就只能对当前锁定的表操作,操作其他的表将会报错( ERROR 1100 (HY000): Table 'xxx' was not locked with LOCK TABLES
)
0、在存储引擎的不同的上面 加上 lock tables xxx read 后,在其他线程 还是可以对表进行写操作的。(比如:myisam引擎的表)
MDL(元数据锁)
不需要显示的使用,在访问一个表时会自动加上,主要用于隔离, dml和ddl操作之间的干扰(对同一个表操作,线程A查询表 t1数据,线程B删除 表t1的字段,避免这种并发操作,故使用MDL加锁操作)
事务提交之后才会释放 【锁】
读读共享,读写互斥,写写互斥。
当对数据做 DML(数据操纵语言,curd)操作是,会申请 MDL,读锁
当对数据做 DDL (数据定义语言,alter),会申请 MDL,写锁
意向锁
意向锁是一种特殊的表级别锁,取得行的共享锁和排他锁之前需要先取得表的意向共享锁(IS)和意向排他锁(IX),意向共享锁和意向排他锁都是系统自动添加和自动释放的,整个过程无需人工干预
主要是用来辅助表级和行级锁之间的冲突判断。
自增锁
自增锁是一种特殊的表级别锁,如果一个表的某个行具有 AUTO_INCREMENT 的列,则一个事务在插入记录到这个表的时候,会先获取自增锁,保证自增的连续性。
行级锁
操作表时,对命中的索引的记录或者范围加上锁,行锁细分为 意向锁,记录锁,间歇锁,临键锁。
- 特点
0、开销大,加锁慢,会出现死锁,锁力度小,锁冲突的概率低,并发度高,
0、行锁是针对索引加锁的,注意,(检索数据需要通过索引,因为Innodb是通过索引的索引项加锁来实现行锁的),记录行中持有改索引的将会加锁。
0、如果没有 用到行锁,则可能会使用锁住整个表。(注意这个用的不是表锁,而是 临键锁next-key lock来锁住整张表)
- 加锁方式
显示加锁:
共享锁:select * from tableName where ... + lock in share mode 排他锁:select * from tableName where ... + for update
隐式加锁 :
在 update 和 delete 时候,对操作命中索引的记录增加锁。
- 衍生的其他算法锁
0、记录锁
0、间歇锁(RR的事务隔离级别,gap lock)
0、临键锁(next-key lock)
页级锁
页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁.表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。BDB支持页级锁
Q&A
表锁innodb中当前会话lock了一张表后,就只能对当前锁定表操作,为什么这么设计?
既然你都 锁定这张表了,为什么不操作者张表呢,然后unlcok,锁定却不使用,岂不是锁定是多此一举。
在当前会话中,锁定了表后,就不能操作其他非锁定的表了。如果操作则提示 ERROR 1100 (HY000): Table 'xxx' was not locked with LOCK TABLES
- 注意
操作一:
lock tables t_a read
lock tables t_b read ,则 t_a的锁就会被释放。当前会话中 lock的操作后者会覆盖前者
操作二:
lock tabels t_a read ,t_b read 则会锁定这2张表
如何理解 表锁的开销小,加锁快的这句话呢?
可以对比行锁,不向行锁那样,在做操作的时候,还需要锁定 索引影响的记录行数,逻辑复杂,开销大,