文章目录加载中

数据事务-不同隔离级别带来的异常

# 场景

目前,主流 db 都支持事务。但事务保证完全 ACID 是有代价的。

所以有时候会为了性能,在某些场景种,弱化事务的 ACID。这是通过设置不同的隔离级别来实现的。

不同的隔离级别能解决不同的读写异常场景,要了解这些读写异常场景,才能根据情况选择合适的隔离级别。

# 脏读(读取未提交的数据)

如果一个事务 A 向数据库写了数据,但事务还没提交或终止,另一个事务 B 就看到了事务 A 写进数据库的数据,这就是脏读。

# 读偏 / 不可重复读(前后多次读取,数据内容不一致)

事务 A 读取数据,此时为 20;事务 B 执行数据更新,变为 30 并且提交;事务 A 还没结束,需要再次读取数据,此时为 30。

对比脏读:脏读是读取另一个事务未提交事务,不可重复读是在一次事务中,读到两种数据状态。

# 幻读(前后多次读取,数据总量不一致)

一个事务的写入改变了另一个事务的查询结果的正确性,这就是幻读。

例如:第一个事务读取一个结果集后,第二个事务,对这个结果集经行增删操作并提交;然而第一个事务中再次对这个结果集进行查询时,数据发现丢失或新增。

# 脏写

当两个事务同时尝试去更新某一条数据记录时,就肯定会存在一个先一个后。而当事务 A 更新时,事务 A 还没提交,事务 B 就也过来进行更新,覆盖了事务 A 提交的更新数据,这就是脏写。

# 更新丢失

两个事务并发写入的时候,其中一个事务的修改可能丢失,因为写入的内容没有包括第一个事务的修改。

例如:事务 A 和 B 同时读取到数据 a,将其更新为 b,同时提交,那么 A 和 B 只有一个会成功。

# 写偏

假设公司里可以同时有多位员工值班,但至少有一位员工在值班。员工可以申请不值班,只要至少有一个同事正在值班,申请即可通过。

此时,小明和小红是两位值班员工。他们都决定请假,恰好在同一时间点击按钮下班。

创建两个事务,应用首先检查是否有两个或以上的员工正在值班。两个事务的读取都返回当前值班员工数量为 2。所以小明/小红都成功更新自己的记录休班了,两个事务更新成功。

但是结果是不满足最初设定的条件:至少有一位员工在值班。

# 参考链接

本文来自心谭博客:xin-tan.com,经常更新web和算法的文章笔记,前往github查看目录归纳:github.com/dongyuanxin/blog