MySQL作为常用的关系型数据库,通过事务隔离级别来平衡并发性能和数据一致性,不同的隔离级别对应不同的数据读取规则,也会产生不同的并发异常问题。了解这些隔离级别的特性,是开发高可靠数据库应用的基础。

什么是事务隔离级别
当多个事务同时操作数据库中的同一批数据时,可能会出现脏读、不可重复读、幻读等问题。事务隔离级别就是数据库定义的一套规则,用来规定一个事务在修改数据时,其他事务能够看到哪些数据变化,从而控制并发场景下的数据访问行为。
MySQL支持的四种事务隔离级别
1. 读未提交(READ UNCOMMITTED)
这是最低的隔离级别,一个事务可以读取到其他事务还没有提交的数据。这种级别下并发性能最高,但是会出现所有类型的并发异常问题。
比如事务A修改了某条数据但还没提交,事务B就能读到修改后的数据,如果事务A之后回滚,事务B读到的数据就是无效的,这就是脏读问题。
2. 读已提交(READ COMMITTED)
该级别要求一个事务只能读取到其他事务已经提交的数据,解决了脏读的问题,但是会出现不可重复读的问题。
不可重复读指的是同一个事务内,两次读取同一行数据,得到的结果不一致。比如事务A第一次读取某行数据后,事务B修改并提交了这行数据,事务A再次读取时就会得到不同的结果。
3. 可重复读(REPEATABLE READ)
这是MySQL的默认事务隔离级别,它保证了在同一个事务中,多次读取同一范围的数据时,得到的结果是一致的,解决了不可重复读的问题,但是理论上还是可能出现幻读。
幻读指的是同一个事务内,两次执行相同的查询条件,返回的记录数量不一致。比如事务A第一次查询符合条件的记录有3条,事务B新增了1条符合条件的记录并提交,事务A再次查询时就会得到4条记录,就像出现了幻觉一样。
不过MySQL的InnoDB引擎在可重复读级别下,通过Next-Key Lock锁机制,已经很大程度上避免了幻读的问题。
4. 串行化(SERIALIZABLE)
这是最高的隔离级别,所有的事务都会串行执行,完全避免了脏读、不可重复读、幻读的问题,但是并发性能最低,因为事务只能一个接一个执行,无法并发处理。
四种隔离级别对比
我们可以通过下表直观地看到不同隔离级别对并发异常问题的解决情况:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 并发性能 |
|---|---|---|---|---|
| 读未提交 | 可能出现 | 可能出现 | 可能出现 | 最高 |
| 读已提交 | 不会出现 | 可能出现 | 可能出现 | 较高 |
| 可重复读 | 不会出现 | 不会出现 | 可能出现(InnoDB已优化避免) | 中等 |
| 串行化 | 不会出现 | 不会出现 | 不会出现 | 最低 |
如何查看和设置事务隔离级别
查看当前隔离级别
可以通过以下SQL语句查看当前会话或者全局的事务隔离级别:
-- 查看当前会话的事务隔离级别 SELECT @@transaction_isolation; -- 查看全局的事务隔离级别 SELECT @@global.transaction_isolation;
设置事务隔离级别
设置事务隔离级别可以针对全局或者当前会话,语法如下:
-- 设置全局事务隔离级别为读已提交 SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 设置当前会话的事务隔离级别为可重复读 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
需要注意的是,全局设置对之后新建立连接的事务生效,已经存在的连接不会受影响;会话设置只对当前连接生效。
隔离级别的选择建议
在实际开发中,我们可以根据业务场景选择合适的隔离级别:
- 如果业务对数据一致性要求不高,更追求并发性能,比如一些日志记录、统计类场景,可以选择读已提交级别。
- 大部分常规业务场景,使用MySQL默认的可重复读级别即可,它已经能满足大多数数据一致性需求,同时兼顾了一定的并发性能。
- 如果业务对数据一致性要求极高,比如金融转账、库存扣减等场景,需要完全避免所有并发异常,可以选择串行化级别,不过需要接受并发性能下降的代价。
- 读未提交级别因为存在严重的脏读问题,实际开发中很少使用,不建议选择。
总结
MySQL的四种事务隔离级别各有特点,没有绝对的好坏之分,只有是否适合当前业务场景的区别。开发者需要清楚每种级别的特性和适用场景,结合业务的数据一致性要求和性能需求做出选择,才能既保证数据的正确性,又让系统有不错的并发处理能力。