作者:海鹰
此教程讲述数据库事务并发可能发生的问题,以及四种隔离级别
版权所有,未经允许,请勿随意转载。
事务并发可能发生的问题
丢失更新( Lost Update )
表现:当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其它事务的存在,最后的更新将重写其它事务提交的更新,这将导致数据丢失。
解决方法:对行加锁,只允许一个更新事务。
第一类丢失更新
示例
| 时间 | 取款事务A | 存款事务B |
|---|---|---|
| T1 | 开始事务 | |
| T2 | 开始事务 | |
| T3 | 查询账户余额为1000元 | |
| T4 | 查询账户余额为1000元 | |
| T5 | 汇入100元把余额改为1100元 | |
| T6 | 提交事务 | |
| T7 | 取出100元把余额改为900元 | |
| T8 | 撤销事务 | |
| T9 | 余额恢复为1000元(丢失更新) | |
| T10 | 结束 | 结束 |
第二类丢失更新
示例
| 时间 | 取款事务A | 转账事务B |
|---|---|---|
| T1 | 开始事务 | |
| T2 | 开始事务 | |
| T3 | 查询账户余额为1000元 | |
| T4 | 查询账户余额为1000元 | |
| T5 | 取出100元把余额改为900元 | |
| T6 | 提交事务 | |
| T7 | 汇入100元 | |
| T8 | 提交事务 | |
| T9 | 把余额改为1100元(丢失更新) | |
| T10 | 结束 | 结束 |
脏读( Dirty Read )
表现:读取到其他事务中未提交的数据。
解决方法:如果在第一个事务提交前,任何其它事务不可读取其修改的值。
示例
| 时间 | 取款事务A | 转账事务B |
|---|---|---|
| T1 | 开始事务 | |
| T2 | 开始事务 | |
| T3 | 查询账户余额为1000元 | |
| T4 | 汇入100元把余额改为1100元 | |
| T5 | 查询账户余额为1100元(读取脏数据) | |
| T6 | 回滚 | |
| T7 | 取款1100元 | |
| T8 | 提交事务失败 | |
| T9 | 结束 | 结束 |
不可重复读( Non-repeatable Read )
表现:在一个事务中前后两次读取的结果不一致,导致了不可重复读。
解决方法:如果只有在修改事务完全提交之后才可以读取数据,则可以避免该问题
示例
| 时间 | 取款事务A | 转账事务B |
|---|---|---|
| T1 | 开始事务 | |
| T2 | 开始事务 | |
| T3 | 查询账户余额为1000元 | |
| T4 | 汇入100元把余额改为1100元 | |
| T5 | 提交事务 | |
| T6 | 查询账户余额为1100元 | |
| T7 | 提交事务 | |
| T8 | 结束 | 结束 |
幻读( Phantom Read )
表现:当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入新记录或删除旧记录,当其它事务再次读取某个范围内的记录时,会产生幻行(Phantom Row)。
解决方法:如果在操作事务完成数据处理之前,任何其它事务都不可以添加新数据,则可以避免该问题。
示例
| 时间 | 查询学生事务A | 插入新学生事务B |
|---|---|---|
| T1 | 开始事务 | |
| T2 | 开始事务 | |
| T3 | 查询学生为10人 | |
| T4 | 插入一个新学生 | |
| T5 | 查询学生为11人 | |
| T6 | 提交事务 | |
| T7 | 提交事务 | |
| T8 | 结束 | 结束 |
事务隔离级别
未提交读( READ UNCOMMITTED )
在该级别,事务中的修改,即使没有提交,对其它事务都是可见的。因此,在这个级别会导致脏读。
这个级别会导致很多问题,从性能上来说,这个级别不会比其它的级别好太多,但却缺乏其它级别的好处,除非真的有非常的必要,在实际应用中很少使用。
提交读( READ COMMITTED )
一个事务开始时,只能“看见”已经提交的事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其它事务都是不可见的。在这个级别会导致不可重复读。
可重复读( REPEATABLE READ )
该级别保证了在同一个事务中多次读到同样记录的结果是一致的。
在这个级别无法解决幻读问题。
可串行化( SERIALIZABLE )
最高的隔离级别,强制事务串行执行。
这个级别会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题,实际应用中也很少用到这个隔离级别。
只有在非常需要确保数据的一致性,而且可以接受没有并发的情况下,才考虑该级别。
总结
| 隔离级别 | 脏读可能性 | 不可重复读可能性 | 幻读可能性 | 加锁读 |
|---|---|---|---|---|
| READ UNCOMMITTED | YES | YES | YES | NO |
| READ COMMITTED | NO | YES | YES | NO |
| REPEATABLE READ | NO | NO | YES | NO |
| SERIALIZABLE | NO | NO | NO | YES |
结语
本教程到此结束,欢迎指正,互相交流。
本教程中的示例来源于马士兵大神的视频教程。
版权所有,未经允许,请勿随意转载。