[转载]数据库事务的四大原则以及隔离级别
转载信息
- 作者:Shi Peng
- 发布时间:2020-10-27 17:54:04
- 原始链接:数据库事务的ACID四大原则 学习笔记
四大原则
- A 代表Atomicity,即原子性。表示组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有的操作执行成功,整个事务才提交。事务中的任何一个数据库操作失败,已经执行的任何操作都必须被撤销,让数据库返回初始状态。
- C 表示Consistency,即一致性。事务操作成功后,数据库所处的状态和他的业务规则是一致的,即数据不会被破坏。如A账户转账100元到B账户,不管操作成功与否,A和B账户的存款总额是不变的。数据库事务在实现了另外三个原则的情况下,一致性就已经实现了。业务的一致性需要开发者决定。
- I 表示Isolation,即隔离性。在并发数据操作时,不同的事务拥有各自的数据空间,他们的操作不会对对方产生干扰。准确地说,并非要求做到完全无干扰。数据库规定了多种事务隔离界别,不同的隔离级别对应不用的干扰程度,隔离级别越高,数据一致性越好,但并发性越弱。
- D 表示Durability,即持久性。一旦事务提交成功后,事务中所有的数据操作都必须被持久化到数据库中。即使在事务提交后,数据库马上崩溃,在数据库重启时,也必须保证能够通过某种机制恢复数据,例如事务日志恢复。
隔离不好容易造成的问题
脏读
脏读指一个事务读到了另一个事务的中间结果,还用转账举例:
当A给B转账的事务没有执行完,另一个事务就读取了它的中间结果,就有可能造成脏读。因为万一之前的事务回滚,那么新读取到的结果就是错的,和A账号回滚之后的余额就不一致了。
不可重复读
不可重复读的意思是说,在一个事务中,我们读取了某个数据两次。刚好在这两次中间,有另一个事务修改了这条数据,那么同样会引起数据错误,因为这两次读取到的结果不一致。
比如我们对A账户的一个事务还没有结束,这时它的结果就被另一个事务修改了,那么程序就会发生错乱,因为读到了它没有预料到的修改。
解决方法就是针对当前修改的数据进行隔离,同一时刻只允许一个事务对该条数据进行修改,以保证数据的一致性。
幻读
幻读就是一个事务读取两次,读到的数据条数不一致。这点和不可重复读非常类似,不过不同的是不可重复读是确定的某一条数据,而幻读是指整个数据库或者整个表而言。
要解决也很简单,因为幻读是其他事务修改其他数据产生的,所以要排除掉这种情况,只针对我们修改的数据进行加锁和隔离是不够的,我们需要将整个数据库,或者是分区进行隔离,同一时刻,只允许一个事务对一个分片或数据库表进行修改。
更新丢失
更新丢失的定义很直观,当我们修改一条数据的时候,另一个事务也在修改这条数据,导致后者的修改覆盖了前者修改的内容。
解决的办法是做好隔离操作,在一个事务写入完成之前,禁止其他事务写入。即更新丢失是在并发场景下出现的错误。
四种隔离级别
隔离级别 | 脏读 | 更新丢失 | 不可重复读 | 幻读 | 并发模型 | 更新冲突检测 |
---|---|---|---|---|---|---|
未提交读 Read uncommited | yes | yes | yes | yes | 悲观 | no |
已提交读 Read commited | no | yes | yes | yes | 悲观 | no |
可重复读 Repeatable Read | no | no | no | yes | 悲观 | no |
可串行读 Serializable | no | no | no | no | 悲观 | no |
从上到下,对应四种隔离级别,越往下隔离级别越高,能够解决的隔离性问题也就越多,同样的,用到的锁也就越多,系统的性能也就越差。
现在分别看下数据库的四种隔离级别:
- 未提交读:在读时不会判断是否可能会读到没有提交的数据,所以他的隔离性最差,连最简单的脏读都无法解决。
- 已提交读:通过锁限制了只会读取已经提交的数据,读数据的时候使用共享锁,在读取完成后立即释放。已提交读级别可解决脏读问题,也是 SQL Server 的默认隔离级别。
- 可重复读:读取过程和已提交读级别一样,但在读取时会保持共享锁,直到事务结束。跟已提交读不同的是,只要一个事务没有结束,锁就不会释放,其他事务无法更新数据,保证了不会出现不可重复读。
- 可串行读:在事务进行中,不仅会锁定受影响的数据本身,还会锁定整个范围。这就阻止了其他事务影响整体的情况出现。