事务并发存在的问题(脏读、不可重复读和幻读)
大约 4 分钟
事务并发存在的问题(脏读、不可重复读和幻读)
事务处理如果,并发执行事务时通常会发生以下问题:
脏读(Dirty Read):。
- 例如当事务A和事务B并发执行时,当事务A更新后,事务B查询读取到A尚未提交的数据,此时如果事务A rollback了,那事务B读到的数据就不是数据库所存放的数据了,而是无效的脏数据(脏读必须杜绝,因为事务没有commit;而不可重复读和幻读不一定出问题,因为事务已经commit)
不可重复读(NonRepeatable Read):一个事务的操作导致另一个事务 。
例如当事务A和事务B并发执行时,当事务B查询读取数据后,事务A 更改事务B查询到的数据,此时事务B再次去读该数据,发现前后两次读的数据不一样(事务B读取了事务A已commit的数据)
幻读(Phantom Read):一个事务的操作导致另一个事务前后。
- 例如 当事务A和事务B并发执行时,当事务B查询读取数据后,事务A或者了一条满足事务B查询条件的记录,此时事务B再去查询,发现查询到前一次不存在的记录,或者前一次查询的一些记录不见了(事务B读取了事务A新增加的数据或者读到事务A删除的数据)
在有些场景下,不可重复读和幻读一定程度上是可以允许的,不一定非要杜绝(通过设置不同的隔离级别解决),由应用场景需求决定
- 脏读举例:张三的账户还剩100块,他同时发起两个事务,事务A转账50,事务B购买价格为80的水杯,事务A现对张三的余额减50,然后给另一个人余额加50。由于没有隔离控制,事务B购买水杯前先读取余额,发现只有50,无法购买茶杯,于是茶杯购买失败。此时事务A执行异常,将张三的余额回滚为事务执行前的状态,余额为100。当前场景中事务B读到了事务A还没有commit的数据50,发生了脏读,任何业务场景下都必须杜绝
- 不可重复读举例:首先事务B查询余额,发现为100。事务A完成转账50,并且commit,事务B再次查询余额,发现变成了50,在某些业务场景下是可以允许的,不一定非要杜绝
- 幻读举例:事务B查询年龄为20的人,发现有5个。事务A插入或删除了年龄为20的记录,并且commit,事务B再次查询年龄为20的人,发现已经不是5个人了,幻读也是在某些业务场景下是可以允许的,不一定非要杜绝
事务相关命令
一般我们业务上如果要考虑到事务处理,我们需要设置为手动提交方式,如果一个事务包含多个SQL,若是自动提交方式,一句SQL执行完就自动提交了,后面的SQL万一执行失败就无法正常rollback,无法保证事务的原子特性
BEGIN
:开启一个事务 COMMIT
:提交一个事务 ROLLBACK
:回滚一个事务到初始的位置 SAVEPOINT point1
:设置一个名字为point1的保存点 ROLLBACK TO point1
:事务只回滚到保存点point1,而不是回滚到初始状态SET TRANSACTION_ISOLATION=‘REPEATABLE-READ’
:设置事务的隔离级别SELECT @@TRANSACTION_ISOLATION
:查询事务的隔离级别