MySql InnoDB设置为autocommit off并使用默认隔离级别REPEATABLE READ。有两种情况,两个不同的事务T1和T2在下面的时间顺序中运行,
1)
time T1 T2
t1 update row 1->OK
t2 update row 2->OK
t3 update row 2->wait->timeout error
t4 commit or rollback or retry t3
T1在t3获得超时错误,因为它无法抓取第2行上的T2尚未释放的写锁定,然而,如果T1在t4提交,则导致T1的“部分”更新,即第1行更新但行2没有,因此这种做法违反了ACID的“原子性”规则。
根据ACID的“原子性”规则,交易应该“完成”成功或失败但不是部分。
APP必须要求T1回滚或在t3接收到错误之后在t4提交之前重试超时更新直到成功,从而实现原子性规则。
2)
time T1 T2
t1 update row 1->OK
t2 update row 2->OK
t3 update row 2->wait
t4 update row 1-> DB detects deadlock then forces T2 rolled back
wait->OK
在1)数据库只向APP发送超时错误,由APP决定是否回滚T1,但在2)中,不仅DB检测到死锁错误,而且还用于滚动可能的死锁T2。
从理论上讲,1)DB也可以用来回滚T1,但是2)DB可能只取消导致死锁的操作,然后向APP发送死锁错误,由APP决定是否回滚T2。
问题在于,在DB级别上首先检测到错误时,DB选择具体条件来选择APP或其自身是否应该处理回滚。
非常感谢!
回滚应始终由客户端应用程序处理,而不是数据库。客户端可能正在执行许多不同的操作作为单个“工作单元”,因此,客户端应该控制何时将该工作投入数据库或回滚。
参考 你可以参考Tom Kyte的这个helpful link,他对这个问题非常强烈,他甚至建议从PL / SQL中删除提交/回滚(Oracle的程序语言;我知道你的数据库是mysql,但概念保持不变)。
客户端应用程序的另一个令人信服的理由是,唯一可以真正控制事务流的事情应该是
a)提交或b)回滚
这是工作。 (连同触发器,自治事务和其他人,如果我有办法,我会在plsql中取消提交和回滚:)