欢迎您的访问
专注架构,Java,数据结构算法,Python技术分享

mysql-innodb-锁

写在最前

这是读书笔记,Mysql,innodb系列一共3篇。

  • Mysql-innodb-B+索引
  • Mysql-innodb-锁
  • Mysql-innodb-事务预计20200530)

锁基本概念

锁类型 说明 锁级别
意向共享锁 IS Lock 事务想要获得一张表中某几行的数据的共享锁 表级别锁
意向排他锁IX Lock 事务想要获得一张表中某几行数据的排他锁 表级别锁
共享锁S Lock 允许事务读取一行数据 行级别锁
排他锁X Lock 允许事务更新或删除一条数据 行级别锁

加锁方式

记录r进行上X锁,先对数据库A、表、页上加意向锁IX,才能对记录r上X锁。

兼容性

IS IX S X
IS 兼容 兼容 兼容 不兼容
IX 兼容 兼容 不兼容 不兼容
S 兼容 不兼容 兼容 不兼容
X 不兼容 不兼容 不兼容 不兼容

锁的监控表

查询锁的情况:information_schema下

  • innodb_trx事务表
  • innodb_locks锁表
  • innodb_lock_wait锁等待表

锁算法

3种锁算法

Record Lock

单行记录加锁

Gap Lock

Gap Lock间隙锁,锁一个范围

阻止多个事务将记录插入到同一范围内

Next Key Lock

Next Key Lock:Record Lock+Gap Lock,锁一个范围+锁一个记录

查询的列是唯一索引的情况时,降级为Record Lock。

举例说明

建表插入数据

CREATE TABLE z(
a INT,
b INT,
PRIMARY KEY(a),
index index_b(b)
);
INSERT INTO z SELECT 1,1;
INSERT INTO z SELECT 3,1;
INSERT INTO z SELECT 5,3;
INSERT INTO z SELECT 7,6;
INSERT INTO z SELECT 10,8;

 

会话A

begin;SELECT*FROM z WHERE b=3 FOR UPDATE;

 

68_5.png

会话B

begin;SELECT*FROM z WHERE a=5 LOCK IN SHARE MODE;

 

68_8.png

不能执行Record Lock 锁定了5

68_9.png

2. INSERT INTO z SELECT 4,2;    

 

68_12.png

不能执行有Gap Lock

68_13.png

非一致性锁定读/一致性锁定读

非一致性锁定读

1、 不需要等待访问的行上X锁的释放,直接读快照,提高了数据库的并发性。

2、 快照数据来自undo段。undo段会用在事务回滚,所以快照数据本身没有额外开销。

3、 读快照信息不需要上锁,没有事务需要处理历史数据。

READ COMMITTED和 REPEATABLE READ快照定义的区别

隔离级别 读取的快照数据 是否默认
隔离级别
存在的问题
READ COMMITTED 读锁定行最新的一份提交过数据 会出现幻读
REPEATABLE READ 读锁定行事务开始前的版本

一致性锁定读

锁定读的语句 加锁类型 注意事项
select … for update 加X锁 务必加上BEGIN,
START TRANSACTION或者
SET AUTOCOMMIT=0
select … lock in share mode 加S锁

锁常见问题

脏读,违反隔离性Isolation

不同的事务下,当前事务可以读到另外事务未提交的数据。

read uncommitted隔离级别下会发生

不可重复(Phantom Problem幻读)

一个事务内两次读到的数据是不一样的情况(当前事务没有结束。另外一个事务修改了)。

READ COMMITTED下会发生,会读到已经提交的数据 。

默认的事务隔离级别是

REPEATABLE READ。采用Next-Key Locking的算法,解决。

锁一个范围+锁一个记录。

丢失更新

任何隔离级别下都不会发生,但是应用层面会发生.

//假设id=3的账号余额为100,A事务转账99,
Update t set a=1 where id=3
//B事务转账1
Update t set a=99 where id=3
//B事务后提交,最后余额是99,A事务的丢失了

 

解决方式:

串行化处理,乐观锁等

阻塞

一个事务中的锁需要等待另一个事务中的锁释放它所占用的资源

innodb_lock_wait_timeout来控制等待时间默认50s

innodb_rollback_on_timeout设置超时时是否回滚,默认off,不回滚。

死锁

两个事务,争夺锁,相互等待。

死锁发生的概率一般很低

  • 系统中事务的数量(n),数量越多发生死锁的概率越大
  • 每个事务操作的数量(r),每个事务操作的数量越多,发生死锁的概率越大
  • 操作数据的集合(R),越小则发生死锁的概率越大

解决方式:

设置超时,等待超时的回滚,没有超时的继续,但是并发下降

innodb_lock_wait_timeout来控制等待时间默认50s

通常来说InnoDB存储引擎选择回滚undo量最小的事务

补充2-自增长与锁

自增长的列,必须是索引,且必须是索引的第一个列。

AUTO-INC Locking:

当对含有自增长的计数器的表进行插入操作时,这个计数器会被初始化。

执行: SELECT MAX(auto_inc_col)FROM t FOR UPDATE;

插入操作会依据这个自增长的计数器值加1赋予自增长列

该锁在执行完插入自增长值的SQL后释放

提高了部分性能,但是对应insert select会受影响,需要等待另外一个事务的完成AUTO-INC Locking。

Mysql5.1.22后,提供了轻量级互斥量,在内存中计算自增值提高性能

补充3-外键与锁

innodb外键自动加索引

插入或更新数据时,

先使用SELECT…LOCK IN SHARE MODE方式,即主动对父表加一个S锁。

赞(0) 打赏
版权归原创作者所有,任何形式转载请联系作者;码农code之路 » mysql-innodb-锁

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏