MYSQL默认情况下 MYSQL 是ACID 吗?

得意犹堪夸世俗,诏黄新湿字如鸦。这篇文章主要讲述MYSQL默认情况下 MYSQL 是ACID 吗?相关的知识,希望能为你提供帮助。

最近的世界变化是快, 平行宇宙"被发现", 地球人是外星人的培育的"猿猴",到被抛弃,每天都在刷新.  前几天的mysql的事务错误不会滚的问题, 有同学反映没有太明白.

今天就以这个作为一个主题来做, 题目有点颠覆三观. 首先开头要说的是,  MYSQL 默认情况下事务没有原子性.



首先什么是原子性, 的从事务说起,事务通常由多个语句组成。原子性保证每个事务被视为一个单独的“单元”,要么完全成功,要么完全失败,如果组成事务的任何一条语句失败,整个事务就会失败,而数据库将保持不变。


触发事务回滚的三种可能的方式中

上图是官方文档中的内容, 重要的是下面这句
A lock wait timeout causes InnoDB to roll back only the single statement that was waiting for the lock and encountered the timeout


在高并发的MYSQL 数据库服务器中,死锁和锁等待都是很正常的事情,当然可以从数据库和应用两个部分和不同的手段来解决问题.
When a transaction rollback occurs due to a deadlock or lock   wait timeout, it cancels the effect of the statements within   the transaction. But if the start-transaction statement was a   START   TRANSACTION or   BEGINstatement, rollback does not cancel that statement. Further   SQL statements become part of the transaction until the         occurrence of COMMIT,   ROLLBACK, or some SQL statement that causes an implicit commit.
上面那段加粗的字体的英文就是今天这篇文字的重点 become part of the transaction ,也就是说,MYSQL  的ACID  ,  Atom  这一项 破功了.


可能有人还没觉得有什么事情,我们来一个业务说说这个问题


银行有一个业务,发放工资的业务,  在程序中执行了如下语句


Begin;


员工1工资账号 +  18000
员工2 工资账号+  24000
员工3工资账号+ 30000
....
...
..
..
..
end;


如果此时银行还有一个session 在操作员工257 的账号,  则上面的事务就会出现锁等待,如果等待超时,则员工257之前的账号都会得到工资, 而257及以下的人都不会得到工资,  按照事务的原子性来说, 这是不能容忍的, 因为很可能这个事务失败,根本就不知道是在第几个员工失败的,  因为失败的事务没有正确回滚
session 1

  session 2



操作步骤是
session 1 begin;
session 1  update bank_s set salary = 16000 where name = Tim;
session 2 begin;
session 2  update bank_s set salary = 13000 where name = Jassica;
session 2  update bank_s set salary = 19000 where name = Tim;
session 2 报错    Lock wait timeout exceeded; try restarting transaction
session 1 commit;
session 2 commit;
根据数据库ACID的原理,  可以看到结果,地区在session2  失败后,正确没有报错的  update bank_s set salary = 13000 where name = Jassica;   也回滚了并未进行更新.  这里面的原因

我们调整相关的参数





重新将上面的过程做一遍

结果就不对了,Jassica 的工资由于处在SESSION 的事务中,应该不能被更新应该回滚, 但实际上jassica 的记录已经被更新了.


这是非常重要的一个问题,在某些系统中这样的问题,或偶发的问题是无法被接受的,例如扣款, 放款,  一批放款中,如果有一笔是错误的情况下,应该这个事务要进行全部回滚,因为程序会进行重试, 但如果和上面的结果一样,则很可能造成重要数据的严重的失误和失准. 这样的系统谁敢用????


所以建议将  Innodb_rollback_on_timeout 全部置于ON 的状态, 方式关键系统在偶然的情况下,数据错误失准,导致业务损失.



【MYSQL默认情况下 MYSQL 是ACID 吗?】


    推荐阅读