Mysql笔记



简介

Mysql笔记,主要讲解Mysql的Innodb引擎。

事务的四大特性ACID

Innodb事务隔离级别

索引

底层结构

特性

优化

redo log

undo log

MVCC

锁的种类

事务隔离级别RC和RR的锁

Innodb事务级别RR幻读问题

RR级别下是否能防止幻读,为什么?答案是可以的,不同一般数据库的实现。

有两个原因:

  1. 实现了MVCC,如select count这种是快照读,总是快照数据,不会获取到其他事务造成的不一致数据。
  2. 当进行当前读的时候,如insert操作,因为有gap lock的存在,必然能防止其插入。

有人会说如果在一个隔离级别RR下,有两个事务a和b,a开启事务,先select获取1行数据,此时b delete此行数据并提交事务,然后a update这行数据发现不存在,这不就是幻读么?

其实这有一个概念理解有误或者使用有误,因为select是快照读,update是当前读,数据并不在同一时空上。这里只要进行select for update保证当前读即可。

为什么RR级别能解决幻读但生产线上却不用?

就是因为有gap锁的存在,经常发生死锁,如删除不存在的数据,会导致产生gap锁防止幻读。还会在并发的时候导致record lock升级为next key lock,详细请查看参考一个最不可思议的MySQL死锁分析

保证ACID的实现

原子性A

隔离性I

持久性D

一致性C

附录:锁的日志

开启监控锁,并创建测试表,事务隔离级别RR。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SET GLOBAL innodb_status_output=ON;
SET GLOBAL innodb_status_output_locks=ON;

CREATE TABLE test_lock (
  a int(11) NOT NULL,
  b int(11) DEFAULT NULL,
  c int(11) DEFAULT NULL,
  PRIMARY KEY (a),
  UNIQUE KEY index_b (b),
  KEY index_c (c)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

INSERT INTO test_lock VALUES(1, 11, 111);
INSERT INTO test_lock VALUES(2, 22, 333);
INSERT INTO test_lock VALUES(3, 33, 333);
INSERT INTO test_lock VALUES(4, 44, 444);
INSERT INTO test_lock VALUES(5, 55, 555);

通过 show engine innodb status;查看锁日志

record lock

查询语句:delete from test_lock where b = 22;

1
2
3
4
RECORD LOCKS space id 24 page no 4 n bits 80 index index_b of table `test_db`.`test_lock` trx id 2370 lock_mode X locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
 0: len 4; hex 80000016; asc     ;;
 1: len 4; hex 80000002; asc     ;;

record lock b=0xb=11。

gap lock

查询语句delete from test_lock where c = 400;

1
2
3
4
RECORD LOCKS space id 24 page no 5 n bits 80 index index_c of table `test_db`.`test_lock` trx id 2321 lock_mode X locks gap before rec
Record lock, heap no 5 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 800001bc; asc     ;;
 1: len 4; hex 80000004; asc     ;;

gap lock c=0x1bc=444,444前一个索引是333所以区间gap(333,444)。

next key lock

查询语句:select * from test_lock where c between 400 and 500 for update;

1
2
3
4
5
6
7
8
RECORD LOCKS space id 24 page no 5 n bits 80 index index_c of table `test_db`.`test_lock` trx id 2322 lock_mode X
Record lock, heap no 5 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 800001bc; asc     ;;
 1: len 4; hex 80000004; asc     ;;

Record lock, heap no 6 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 8000022b; asc    +;;
 1: len 4; hex 80000005; asc     ;;

next key lock c=0x1bc=444和c=0x22b=555,区间(333,444)并上(444,555)等于(333,555)。

参考

  1. MySQL 加锁处理分析

  2. 一个最不可思议的MySQL死锁分析

  3. MySQL 5.7 Reference Manual InnoDB Locking