MySQL支持哪些事务隔离级别?
在 MySQL 中,事务隔离级别决定了事务之间如何相互影响,主要有四种:
读未提交:事务可以读取其他事务尚未保存的数据,这可能导致“脏读”问题。
读已提交:事务只能读取已经保存的数据,避免了脏读,但可能导致查询结果不一致。
可重复读:保证在同一个事务中多次查询的结果一致,避免了数据不一致,但可能出现“幻读”。
串行化:所有事务一个接一个执行,完全避免并发问题,但会极大降低性能。
📚 知识内容
👀 1. 读未提交(READ UNCOMMITTED)
在该隔离级别下,一个事务可以读取到另一个事务尚未提交的更改。这个级别存在 脏读 的问题。脏读是指一个事务读取了其他事务未提交的数据,而这些数据可能在后续被回滚,导致读取到的数据不可靠。
示例:事务 A 更新了 products 表的某条记录,但尚未提交,事务 B 就读取到了这个未提交的更新。如果事务 A 最终回滚,事务 B 所读取的数据就变得无效。
– 事务 A
BEGIN;
UPDATE products SET price = 200 WHERE id = 1;
– 事务 B
BEGIN;
SELECT * FROM products WHERE id = 1; – 读取到事务 A 未提交的脏数据
📈 2. 读已提交(READ COMMITTED)
在这个级别下,事务只能读取到其他事务已经提交的数据,从而避免了脏读的问题。然而,它仍然可能会出现 不可重复读。不可重复读是指,在一个事务内,两次查询同样的数据时,返回的结果可能不同,因为在这两次查询之间,其他事务可能修改了数据。
示例:事务 A 读取了一条 products 表的数据,事务 B 修改了这条数据并提交,事务 A 再次读取时,会得到不同的结果。
– 事务 A
BEGIN;
SELECT price FROM products WHERE id = 1; – 查询价格为100
– 事务 B
BEGIN;
UPDATE products SET price = 120 WHERE id = 1;
COMMIT; – 提交事务 B
– 事务 A
SELECT price FROM products WHERE id = 1; – 查询价格变为120
🔁 3. 可重复读(REPEATABLE READ)
在这个隔离级别下,保证了一个事务在其执行过程中,对于相同的查询,始终返回相同的结果,从而避免了不可重复读的问题。但是,在并发环境下,可能会发生 幻读。幻读是指在同一事务内,两次查询得到的结果集行数不同,通常是因为其他事务插入或删除了符合查询条件的数据。
示例:事务 A 查询了 products 表中的数据,事务 B 插入了新数据并提交,事务 A 再次查询时,返回的结果集行数可能会发生变化。
– 事务 A
BEGIN;
SELECT * FROM products WHERE price > 100; – 假设返回3条记录
– 事务 B
BEGIN;
INSERT INTO products (name, price) VALUES (‘Product A’, 150);
COMMIT; – 提交事务 B
– 事务 A
SELECT * FROM products WHERE price > 100; – 返回4条记录
🛑 4. 串行化(SERIALIZABLE)
这是 MySQL 中的最高隔离级别,确保事务完全按顺序执行,相当于将所有事务串行化处理。它可以避免所有并发问题(脏读、不可重复读、幻读),但会显著降低系统的并发性和性能,因为每个事务必须等待前一个事务完成才能开始。
示例:事务 A 和事务 B 都需要更新 products 表的同一条记录,在串行化隔离级别下,两个事务必须顺序执行,后一个事务必须等待前一个事务完成。
– 事务 A
BEGIN;
SELECT * FROM products WHERE id = 1 FOR UPDATE; – 锁定记录
– 事务 B
BEGIN;
SELECT * FROM products WHERE id = 1 FOR UPDATE; – 事务 B 必须等待事务 A 提交后才能继续
🌐 知识拓展
💡 1. 脏读、不可重复读和幻读的概念
脏读(Dirty Read):事务 A 读取了事务 B 未提交的数据。如果事务 B 最终回滚,事务 A 读取的数据会变得无效。
不可重复读(Non-repeatable Read):事务 A 在同一事务中对同一数据进行了两次查询,查询结果不同,因为事务 B 修改并提交了该数据。
幻读(Phantom Read):事务 A 对某一范围的数据进行了查询,在查询之间,事务 B 插入、删除了符合条件的数据,导致事务 A 多次查询时得到不同的行数。
⚙️ 2. 串行化(SERIALIZABLE)级别的优化
在 SERIALIZABLE 级别下,所有的 SELECT 查询都会被隐式地加上 FOR SHARE 锁,这样其他事务不能修改正在读取的数据。为了避免在某些场景下的性能下降,可以考虑在需要高并发的场景下,选择合适的隔离级别(如 READ COMMITTED 或 REPEATABLE READ)来平衡性能与数据一致性。
📝 3. MySQL 默认的隔离级别
MySQL 默认的事务隔离级别是 REPEATABLE READ,这是因为它在保证一致性的同时,也能够提供较好的并发性能。MySQL 使用的 InnoDB 存储引擎通过使用 多版本并发控制(MVCC) 来避免幻读问题,确保数据的一致性。
📊 事务隔离级别的简单原理图
+—————————-+
| 事务隔离级别 |
+—————————-+
| 读未提交 | 读已提交 |
| 脏读 可能 | 不会发生脏读 |
+—————————-+
| 可重复读 | 串行化 |
| 不会发生脏读 | 会串行化执行 |
| 不可重复读可能 | 不会发生脏读 |
| 幻读可能 | 幻读不会发生 |
+—————————-+
通过这些简单的解释与代码示例,相信您对 MySQL 事务隔离级别的理解更加清晰了!🧑💻✨
