mysql锁分类

118 阅读6分钟

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张表

如何理解 表锁的开销小,加锁快的这句话呢?

可以对比行锁,不向行锁那样,在做操作的时候,还需要锁定 索引影响的记录行数,逻辑复杂,开销大,