Skip to content

Latest commit

 

History

History
127 lines (80 loc) · 4.79 KB

事务隔离级别.md

File metadata and controls

127 lines (80 loc) · 4.79 KB

事务隔离级别

通过定义事务隔离级别来控制隔离性。事务的隔离级别规定了数据库系统中一个事务的结果在何时以何种方式对其他并发事务可见。

SQL 标准定义了 4 种隔离级别,强度从低到高:

  1. 未提交读(Read Uncommitted)
  2. 提交读(Read Committed)
  3. 可重复读(Repeatable Read)
  4. 可序列化(Serializable)

随着数据库事务隔离级别的提高,数据库的并发能力也会有所下降。所以,如何在并发性和隔离性之间做好权衡是一个至关重要的问题。

1. 未提交读(Read Uncommitted)

最低的隔离级别,在这种事务隔离级别下,一个事务可以读到另外一个事务未提交的数据

锁实现

  • 事务读,不加锁
  • 事务写,加行级共享锁

示例

顺序 事务1 事务2
1 SELECT age FROM users WHERE id = 1;
2 UPDATE users SET age = 21 WHERE id = 1;
3 SELECT age FROM users WHERE id = 1;
4 rollback;

在上述示例中,事务 1 读了一条事务 2 修改了但最后并未提交的数据,这种错误数据就是脏数据,这种现象称为「脏读」。

脏读」:一个事务读取到另一事务已修改但为未提交的数据。

Read Uncommitted 的事务隔离级别下,会产生脏读问题。为了解决脏读问题,需要使用包括 Read Committed 以上的隔离级别。

2. 提交读(Read Committed)

在一个事务修改数据过程中,如果事务还没提交,其他事务不能读该数据。

锁实现

  • 事务读,读取时加行级共享锁,读完立刻释放
  • 事务写,写入时加行级排它锁,直到事务结束才释放

示例

顺序 事务1 事务2
1 SELECT age FROM users WHERE id = 1;
2 UPDATE users SET age = 21 WHERE id = 1;

commit;
3 SELECT age FROM users WHERE id = 1;

在上述示例中,同一事务 1 两次读取的结果不一致,这种现象称为「不可重复读」。

不可重复读」:在同一个事务中,多次读取同一个数据,前后不一致。

Read Committed 的事务隔离级别下,保证读取的都是已提交的数据,避免了脏读,但是会产生不可重复读的问题。为了解决不可重复读的问题,需要使用 Repeatable Read 以上的隔离级别。

3. 可重复读(Repeatable Read)

MySQL 默认的事务隔离级别。

解决 Read Committed 级别产生的「不可重复读」问题。

锁实现

  • 事务读,加行级共享锁,直到事务结束才释放
  • 事务写,加行级排它锁,直到事务结束才释放

示例

顺序 事务1 事务2
1 SELECT age FROM users WHERE id = 1;

commit;
2 UPDATE users SET age = 21 WHERE id = 1;

commit;

在上述示例中,只有在事务 1 提交之后,事务 2 才能执行写操作,所以事务 1 在提交前对同一数据的多次读取都是一样的。

虽然 Repeatable Read 可以解决「不可重复读」问题,但是还有一种读问题没法解决。

顺序 事务1 事务2
1 SELECT * FROM users WHERE age BETWEEN 10 AND 30;
2 INSERT INTO users VALUES ( 3, 'Bob', 27 );

commit;
3 SELECT * FROM users WHERE age BETWEEN 10 AND 30;

在上述示例中,

  1. 事务 1 的第一次查询条件是 age BETWEEN 10 AND 30,如果有 10 条符合条件的记录,那么会给这 10 条记录加上行级共享锁,并且其他事务无法修改。
  2. 事务 2 向表里插入一条数据,因为没有事务对表加表级锁,所以操作可以执行。
  3. 当事务 1 再执行同样的查询时,返回的结果就变成了 11 条,多出来的就是事务 2 刚插入的那条。

同一个事务中,两次查询的结果集不一致,这种现象称为「幻读」。

幻读」:在同一个事务中,两次完全相同的查询,得到的结果集不同。

为了解决幻读问题,需要使用 Serializable 隔离级别。

4. 可序列化(Serializable)

最高的隔离级别,可以解决「脏读」、「不可重复读」、「幻读」等读问题。但是可序列化对并发性能的影响也是最大的。

锁实现

  • 事务读,读取的时候加表级共享锁,直到事务结束才释放
  • 事务写,写入的时候加表级排它锁,直到事务结束才释放

总结

隔离级别 脏读 不可重复读 幻读
RU
RC x
RR x x
S x x x

参考