再谈ACID
在交易系统中,有了数据库的事务机制,只要确保每一笔交易都在事务中执行,我们的账户系统就很容易保证流水和余额数据的一致性。但是,ACID 是一个非常严格的定义,或者说是理想的情况。如果要完全满足 ACID,一个数据库的所有事务和 SQL 都只能串行执行,这个性能肯定是不能满足一般系统的要求的。
对账户系统和其他大多数交易系统来说,事务的原子性和持久性是必须要保证的,否则就失去了使用事务的意义,而一致性和隔离性其实可以做适当牺牲,来换取性能。所以,MySQL 提供了四种隔离级别,具体来看一下这个表:
RU级别:实际上就是完全不隔离。每个进行中事务的中间状态,对其他事务都是可见的,所以有可能会出现“脏读”。。
序列化级别:具备完美的“隔离性”和“一致性”,性能最差,也很少会用到。
RR(Mysql默认隔离级别)与RC 这两种隔离级别都可以避免脏读,能够保证在其他事务中是不会读到未提交事务的数据,或者通俗地说,只要你的事务没有提交,那这个事务对数据做出的更新,对其他会话是不可见的,它们读到的还是你这个事务更新之前的数据。
查看数据库的隔离级别: SELECT @@global.transaction_isolation, @@transaction_isolation;
不可重复读: 在一个事务执行过程中,它能不能读到其他已提交事务对数据的更新,如果能读到数据变化,就是“不可重复读”,否则就是“可重复读”。
幻读:在A查询某条记录不存在向其中插入某条数据时,另外一事务插入条数据的插入该同样id的数据。执行相同的插入语句时,就会报主键冲突错误,但是由于事务的隔离性,它执行查询的时候,却查不到这条记录,就像出现了“幻觉”一样,这就是幻读。
注意:更新数据后,不能只检查更新语句是不是执行成功了,还需要检查返回值中变更的行数是不是等于 1。因为可能只是更新了 0 条记录的情况。
ACID 是一种理想情况,特别是要完美地实现 CI,会导致数据库性能严重下降,所以 MySQL 提供的四种可选的隔离级别,牺牲一定的隔离性和一致性,用于换取高性能。这四种隔离级别中,只有 RC 和 RR 这两种隔离级别是常用的,它们的唯一区别是在进行的事务中,其他事务对数据的更新是否可见。