mysql事务

32 阅读2分钟

1 事务并行的问题

1.1 脏读

一个事务读到了另一个事务没提交的数据。

1.2 不可重复读

一个事务多次读取同一条数据,但是前后读到的数据不一样。

1.3 幻读

一个事务查询符合条件的数据条数,前后读到的条数不一样

2 隔离级别

2.1 读未提交

直接读取。

2.2 读已提交

每条语句执行时创建readview。

2.3 可重复读

在每个事务开启时创建readview。

mysql默认级别,通过两种方法在一定程度上避免了幻读:

2.3.1 快照读

普通select语句就是快照读,通过MVCC解决幻读

2.3.2 当前读

select for update,通过记录锁 + 间隙锁解决幻读

2.4 串行化

加锁避免并行访问

3 readview

  • creator_trx_id:创建readview的事务id

  • m_ids:创建readview时活跃且未提交的事务id列表

  • min_trx_id:创建readview时最小的事务id

  • max_trx_id:创建readview时要分配给下一个事务的id

在一行记录存储时有两个隐藏列

  • trx_id:最近修改行记录的事务id

  • roll_pointer:每次修改行记录后,旧版本被写到undo日志中,这个指针就是指向undo旧版本的

3.1 隔离原理

事务访问记录时有三种情况:

3.1.1 trx_id < min_trx_id

说明在创建readview前该记录就被修改了,所以对当前事务可见

3.1.2 trx_id >= max_trx_id

说明记录在创建readview之后才被修改的,所以记录对当前事务不可见

3.1.3 trx_id在min_trx_id和max_trx_id之间

这时要判断trx_id是否在m_ids中:

  • 不在,说明记录虽然是在readview创建时正在被修改中,但是此时已经修改它的事务已经提交了,所以记录对当前事务可见

  • 在,记录还在被修改中,所以不可见

读已提交和可重复读的区别就是使用的readview不同,读已提交使用的是当前语句执行时创建的,可重复读使用的是事务开始时创建的。

4 可重复读不能完全避免幻读

以下场景依然会出现幻读

  • 事务a开启

  • 事务b插入一条新数据,然后提交

  • 事务a更新这条新数据,可以更新,虽然a不能select到新数据,但是可以update

  • 事务a再查,就能查到新数据了

事务a:

事务b