数据库隔离级别
<p>隔离级别决定了事务之间的<strong>可见性</strong>规则,直接影响数据库的并发性能和数据一致性。</p><p>SQL 标准定义了 4 种隔离级别,从低到高依次为:<strong>读未提交→读已提交→可重复读→串行化</strong>。隔离级别越高,对并发问题的解决能力越强,但对性能的消耗也越大(因限制了并发操作)。</p>
<h3>一、读未提交(Read Uncommitted, RU)</h3>
<p><strong>定义</strong>:一个事务可以读取另一个事务 <strong>未提交 </strong>的修改。</p>
<p><strong>解决的问题</strong>:无(是最低级别的隔离,几乎不做任何隔离控制)。</p>
<p><strong>存在的问题</strong>:可能出现 <strong>脏读、不可重复读、幻读</strong>。</p>
<p><strong>示例</strong>:</p>
<p>1、事务 B 执行 "修改数据 X 为 100" 但<strong>未提交</strong>;</p>
<p>2、事务 A 读取 X=100;</p>
<p>3、事务 B 回滚(X 恢复为 50),事务 A 读取的 "100" 是无效的(<strong>脏读</strong>)。</p>
<p><strong>适用场景</strong>:极少使用,仅在对数据一致性要求极低、追求极致并发性能时(如实时监控数据,允许临时脏数据)。</p>
<h3>二、读已提交(Read Committed, RC)</h3>
<p><strong>定义</strong>:一个事务只能读取另一个事务<strong>已提交</strong>的修改(未提交的修改不可见)。</p>
<p><strong>解决的问题</strong>:避免 <strong>脏读</strong>(因只能读已提交的数据)。</p>
<p><strong>存在的问题</strong>:可能出现 <strong>不可重复读、幻读</strong>。</p>
<p><strong>示例</strong>:</p>
<p>1、事务 A 第一次读取 X=50;</p>
<p>2、事务 B 修改 X 为 100 并提交;</p>
<p>3、事务 A 第二次读取 X=100(与第一次不一致,<strong>不可重复读</strong>)。</p>
<p><strong>实现原理</strong>:通过 "行级锁" 或 "快照读" 实现(如 Oracle 默认用快照读:每个事务读取数据时,获取该数据的 "已提交版本")。</p>
<p><strong>适用场景</strong>:大多数互联网业务(如电商订单、支付场景),平衡了一致性和并发性能,是 <strong>Oracle、SQL Server 的默认隔离级别</strong>。</p>
<h3>三、可重复读(Repeatable Read, RR)</h3>
<p><strong>定义</strong>:一个事务在执行期间,多次读取同一批数据的结果始终一致(不受其他事务<strong>提交的修改</strong>影响)。</p>
<p><strong>解决的问题</strong>:避免<strong>脏读、不可重复读</strong>。</p>
<p><strong>存在的问题</strong>:可能出现<strong>幻读</strong>(因无法限制其他事务新增 / 删除符合条件的记录)。</p>
<p><strong>示例</strong>:</p>
<p>1、事务 A 第一次查询 "年龄> 18 的用户",返回 10 条;</p>
<p>2、事务 B 新增 1 条 "年龄 = 20" 的用户并提交;</p>
<p>3、事务 A 再次查询 "年龄> 18 的用户",返回 11 条(记录数变化,<strong>幻读</strong>)。</p>
<p><strong>实现原理</strong>:通过 "多版本并发控制(<strong>MVCC</strong>)" 实现(每个事务启动时生成一个 "数据快照",后续读取基于该快照,不受其他事务提交的修改影响)。</p>
<p><strong>特殊说明</strong>:MySQL 的 InnoDB 引擎对 RR 做了增强,通过 "<strong>间隙锁(Gap Lock)</strong>" 避免了部分幻读场景(但并非完全解决,极端情况仍可能出现),因此 InnoDB 的 RR 实际隔离性略高于标准定义。</p>
<p><strong>适用场景</strong>:对数据一致性要求较高的业务(如金融交易、库存管理),是 <strong>MySQL InnoDB 的默认隔离级别</strong>。</p>
<h3>四、串行化(Serializable, S)</h3>
<p><strong>定义</strong>:所有事务 "<strong>串行执行</strong>"(即一个接一个执行,不允许并发操作同一批数据)。</p>
<p><strong>解决的问题</strong>:避免 <strong>脏读、不可重复读、幻读</strong>(是最高级别的隔离,完全保证数据一致性)。</p>
<p><strong>存在的问题</strong>:并发性能极差(因本质是 "单线程" 执行,会导致大量事务等待)。</p>
<p><strong>实现原理</strong>:通过 "<strong>表级锁</strong>" 或 "<strong>范围锁</strong>" 强制事务串行化(如事务 A 操作某范围数据时,其他事务对该范围的读写均被阻塞)。</p>
<p><strong>示例</strong>:</p>
<p>1、事务 A 执行 "查询年龄> 18 的用户" 并准备修改;</p>
<p>2、事务 B 尝试新增 "年龄 = 20" 的用户时,会被阻塞,直到事务 A 完成并释放锁;</p>
<p>3、因此事务 A 两次查询的结果完全一致,无幻读。</p>
<p><strong>适用场景</strong>:仅在对数据一致性要求极高、并发量极低的场景(如银行核心交易的对账操作,不允许任何并发不一致)。</p>
<h3>隔离级别对比</h3>
<table class=" cke_show_border">
<thead>
<tr>
<th>隔离级别</th>
<th>脏读</th>
<th>不可重复读</th>
<th>幻读</th>
<th>并发性能</th>
<th>典型数据库默认值</th>
</tr>
</thead>
<tbody>
<tr>
<td>读未提交(RU)</td>
<td>可能</td>
<td>可能</td>
<td>可能</td>
<td>最高</td>
<td>几乎无数据库默认</td>
</tr>
<tr>
<td>读已提交(RC)</td>
<td>不可能</td>
<td>可能</td>
<td>可能</td>
<td>较高</td>
<td>Oracle、SQL Server</td>
</tr>
<tr>
<td>可重复读(RR)</td>
<td>不可能</td>
<td>不可能</td>
<td>可能</td>
<td>中等</td>
<td>MySQL InnoDB</td>
</tr>
<tr>
<td>串行化(S)</td>
<td>不可能</td>
<td>不可能</td>
<td>不可能</td>
<td>最低</td>
<td>无数据库默认</td>
</tr>
</tbody>
</table>
<h3>不可重复读与脏读的区别</h3>
<ul>
<li><strong>脏读(</strong>Dirty Read<strong>)</strong>:读取到其他事务 <strong>未提交 </strong>的数据;</li>
<li><strong>不可重复读(</strong>Non-repeatable Read<strong>)</strong>:读取到其他事务 <strong>已提交 </strong>的 <strong>修改</strong>。</li>
</ul>
<h3>不可重复读与幻读的区别</h3>
<ul>
<li><strong>不可重复读(</strong>Non-repeatable Read<strong>)</strong>:针对 <strong>已存在 </strong>数据的 <strong>修改</strong>;</li>
<li><strong>幻读(</strong>Phantom Read<strong>)</strong>:针对 <strong>新增或删除 </strong>的数据行。</li>
</ul>
<p style="text-align: right"><span style="color: rgba(53, 152, 219, 1)">人活一世,谋生之道,立世之途,为人之智,尽在书中。-- 烟沙九洲</span></p><br><br>
来源:https://www.cnblogs.com/yanshajiuzhou/p/18999670
頁:
[1]