事务图谱

image.png

事务的特性

原子性(Atomicity)

  • 事务中的操作要么全部成功,要么全部失败
  • MySQL的两阶段提交保证了事务的原子性
  • undo log用来回滚事务的更改

    一致性(Consistency)

  • 事务必须使数据库从一个一致性状态变换到另外一个一致性状态

  • 锁和两阶段提交保证了一致性

    隔离性(lsolation)

  • 事务不能被其他事务的操作数据所干扰

  • 多个并发事务之间要相互隔离
  • 锁和undo log实现了MySQL事务的隔离性

    持久性(Durability)

  • 一个事务一旦被提交,它对数据库中数据的改变就是永久性的

  • redo log实现了MySQL事务的持久性

隔离级别

读未提交(READ UNCOMMITTED)

  • 读、写都不加锁,不隔离
  • 每次查询都查询到数据的最新版本
  • 性能最好,但是等于没有事务,很少采用

读已提交(READ COMMITTED)

  • —般读取时,读取此时已经提交的数据
  • 写数据时,加X锁,提交时释放
  • Oracle数据库的默认隔离级别

可重复读(REPEATABLE READ)

  • 一般读取时,读取本事务开始时的数据
  • 状态写数据时,加X锁,提交时释放
  • MySQL数据库的默认隔离级别
  • MySQL中的可重复读,在写数据加X锁时,另一个事务是可以快照读的。

串行化(SERIALIZABLE)

  • 读加S锁、写加X锁,提交时释放
  • 对于一条数据,同时只能有一个事务进行写操作
  • 事务隔离性最高,性能太差,很少采用

MVCC多版本并发控制

行记录的版本控制

由于undo log的存在,可以从最新版本推算之前版本。
image.png

快照读(一致性非锁定读)

不锁定数据的情况下,读取数据的特定历史版本
版本由事务的具体需求确定:

  • 读已提交:根据每次SELECT时,其他事务的提交情况
  • 可重复读:根据事务开始时,其他事务的提交情况

快照读不需加行锁,属于乐观锁的一种思路。

当前读(一致性锁定读)

  • 读取数据的当前版本,并加锁
  • 若当前版本已经被加锁且不兼容,则阻塞等待
  • X锁:UPDATE、DELETE、SELECT FOR UPDATE
  • S锁: SELECT IN SHARE MODE
  • SERIALIZABLE所有的读都是当前读,加了S锁
  • 当前读需加行锁,为了并发控制

    MySQL不同隔离级别的问题

    脏读:读到了其他事务未提交的数据
    不可重复读:同样的查询读到的数据内容不一样
    幻读:同样的查询读到了更多的数据,记录的条数不一样
    image.png
    在通用的数据库规范里面,可重复读是不需要解决幻读问题的。
    但是MySQL通过间隙锁Next Key锁的进制,部分解决了幻读的问题。

    如何解决幻读问题

  • MySQL在可重复读级别时,通过Next-Key锁解决了幻读问题

  • Next-Key锁是行锁+间隙锁
  • 间隙锁的功能与行锁相同,只是针对间隙加锁
  • 间隙锁不分读写,也可以认为是读锁,不允许在间隙插入
  • 可重复读加锁时,将同时锁住数据及其左右间隙

    Next-Key Lock的加锁逻辑

  1. 加锁时以Next-Key为基本单位

Next-Key就是间隙和它的下一个行记录。

  1. 查找过程中扫描过的范围才加锁
  2. 唯一索引等值查询,没有间隙锁,只加行锁
  3. 索引等值查询最右一个扫描到的不满足条件值不加行锁
  4. 索引覆盖且只加S锁时,不锁主键索引

    示例数据表

    ``sql CREATE TABLEt3(idINT (11)NOT NULL,cINT (11) DEFAULT NULL,dINT (11)DEFAULT NULL,PRIMARY KEY (id), KEYc(c`) )ENGINE =INNODB;

INSERT INTO t3 VALUES ( 0,0,0 ),(10,10,10 ),( 20,20,20 ),( 30,30, 30 ),( 40,40,40 ),( 50, 50, 50 ); ```

等值查询间隙锁

image.png

非唯一索引等值锁

image.png
非唯一索引是可能重复的,需要锁住值左右之间的间隙,防止在间隙范围内提交新的数据。

主键索引范围锁

image.png
主键索引是唯一的,索引30到40之间不需要加间隙锁。

非唯一索引范围锁

image.png
不是唯一索引,以Next-Key为单位进行加锁,最终加锁范围是(10,40)

非索引字段查询

image.png
注意:当前读时,不要查询没有索引的项目,会锁住整张表。