Mysql杂志(三)
事务隔离级别
我们紧接着上篇内容,现在来讲一下什么是事务隔离级别。事务隔离级别 是一套规则,用于决定一个事务对另一个并发事务所做的修改的“可见性”。它核心要解决的是数据库在同时处理多个事务时,如何平衡数据一致性和系统性能(并发能力) 之间的矛盾。更高的隔离级别意味着更严格的数据一致性保证,但会降低并发性能(因为需要更多的锁或版本控制)。更低的隔离级别则提供更高的并发能力,但可能带来数据一致性的风险。
这个也是我们上篇讲到的快照读和当前读的部分原因,以下是四大标准的事务隔离级别从低到高。
隔离级别 | 脏读 | 不可重复读 | 幻读 | 说明 |
---|---|---|---|---|
READ UNCOMMITTED | ❌ 可能发生 | ❌ 可能发生 | ❌ 可能发生 | 限制最弱,并发最高 |
READ COMMITTED | ✅ 避免 | ❌ 可能发生 | ❌ 可能发生 | 只能读到已提交的数据 |
REPEATABLE READ | ✅ 避免 | ✅ 避免 | ❌ 可能发生 | MySQL的默认级别 |
SERIALIZABLE | ✅ 避免 | ✅ 避免 | ✅ 避免 | 限制最强,并发最低 |
三种并发问题解释:
- 1.脏读 (Dirty Read):
- 定义:一个事务读到了另一个未提交事务修改的数据。例子:事务A将余额从100改为200但未提交,事务B读到了200。随后事务A回滚,余额变回100,导致事务B读到的数据是“脏”的、不存在的。
- 2.不可重复读 (Non-Repeatable Read):
- 定义:在同一个事务中,多次读取同一行数据,结果不一致(因为其他已提交事务修改或删除了该数据)。例子:事务A第一次查询余额是100。随后事务B提交了更新,将余额改为200。事务A再次查询,发现余额变成了200。重点:数据行被修改或删除。
- 3.幻读 (Phantom Read):
- 定义:在同一个事务中,多次执行相同的查询,返回的结果集行数不一致(因为其他已提交事务插入了新的数据)。例子:事务A查询年龄小于30的人,返回10条记录。随后事务B提交了一条新的年龄为25的记录。事务A再次执行相同查询,返回了11条记录,就像产生了“幻觉”一样。重点:有新的数据行被插入。
MySQL InnoDB 存储引擎的默认隔离级别是 REPEATABLE READ
。这是一个非常实用的选择,它在保证较强的一致性(避免了脏读和不可重复读)的同时,仍然提供了不错的并发性能。
特别需要注意的是:虽然SQL标准中 REPEATABLE READ
无法解决幻读,但 MySQL 的 InnoDB 引擎通过“Next-Key Locking”算法(间隙锁)在一定程度上防止了幻读的发生。这使得MySQL的 REPEATABLE READ
实际上比标准定义的更强大。
什么情况下当前读/快照读?
其实所有的简单DQL都是快照读,只有加锁的数据才是当前读,那为什么上一篇中共享锁是当前读呢?因为那个表是针对其他事务也要加锁的情况下,为什么排他锁却不可以呢?因为排他锁排斥其他的锁,当前数据有且仅有一个锁才行,所以其他事务会阻塞。
那所以的普通查询都是快照读那怎么保证数据一致性呢?因为上一篇说了快照读都是借助了undolog,而这个存的都是上一个版本的信息,数据根本不正确。那是因为undolog是事务开启的时候开启,事务消亡后没有其他事务使用它就会被清除,所以快照读如果当前没有undolog就会读取磁盘上的数据。
而且可以理解为事务是一条支线,而我们的查询读的都是主线,也就是正确被提交的数据,只有事务提交了才会被合并到主线,否则就会被回滚,事务的这条支线也就被废弃了。这个和GIt有点像。
显式事务和隐式事务
区别显而易见的,显式就是我们开发者自己控制事务边界,什么时候提交由我们自己说了算。而隐式事务就是数据库给我们加的事务,语句的开始前开启,语句的结束后提交,也不是所有的sql都有隐式事务。可以通过SELECT @@autocommit;来查询是否默认打开了隐式事务(Mysql是默认打开的)。
SQL类型 | 是否触发隐式事务 | 示例 |
---|---|---|
DML | ✅ 是 |
|
DDL | ❌ 否(自动提交) |
|
纯查询 | ❌ 否 |
|
SET/SHOW | ❌ 否 |
|
总结
本篇主要是对上一篇内容的补充,提到了事务隔离和显式/隐式事务。