MySQL InnoDB之锁

锁用于控制对共享资源(行记录)的并发访问。

基本锁

latch

锁定的对象是数据结构,锁定时间非常短,没有死锁检测机制。

lock

锁定的对象是数据库中的对象,比如表、页、行。在事务结束后释放,有死锁检测机制。

锁的类型

S

允许事务对一行数据。

X

允许事务删除或更新一行数据。

IS

事务想要获得一张表中某几行的共享锁。

IX

事务想要获得一张表中某几行的排他锁。

一致性非锁定读

如果读取的行正在执行delete或update操作,这时,读取操作不会等待行上锁的释放,而是读取行的一个快照数据(通过undo完成)。

一致性锁定读

select … for update;
select … lock in share mode;

锁的算法

record lock

gap lock

Mysql加锁过程详解(9)-innodb下的记录锁,间隙锁,next-key锁

next-key lock

解决死锁之路 – 常见 SQL 语句的加锁分析

锁问题

脏读

在当前事务下,读到其他事务为提交的数据。

不可重复读(幻象问题)

在同一个事务的两次读数据之间,由于其他事务的修改,该事务内两次读到的数据不一致。

死锁

两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象。

死锁示例

drop table if exists t;
create table t(a int primary key);
insert into t select 1;
insert into t select 2;
insert into t select 5;
时间点session1session2
1begin;
2>select * from t where a=1 for update;
+---+
| a |
+---+
| 1 |
+---+
1 row in set (0.00 sec)
begin;
3>select * from t where a=2 for update;
+---+
| a |
+---+
| 2 |
+---+
1 row in set (0.00 sec)
4>select * from t where a=2 for update;
#deng
5>select * from t where a=1 for update;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
时间点session1session2
1begin;
2begin;
3select * from t
where a=4 for update;
4select * from t
where a<=4 lock in share mode
5>insert into t values(3);
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

检测死锁

1. 超时

2. 等待图(wait-for graph,innodb采用)

在发现死锁后,innodb会回滚一个事务。

锁升级

将锁的粒度降低,例如把行锁升级为页锁,把页锁升级为表锁。
innodb不存在锁升级的问题,它是根据每个事务访问的每个页对锁进行管理,管理采用的是位图的方式。

drop table if exists t;
create table t(
    a int,
    b int,
    key (a),
    key (b)
)engine=innodb;