数据库事务的四大原则以及常见问题

2021/07/28

[转载]数据库事务的四大原则以及隔离级别

转载信息

四大原则

  • A 代表Atomicity,即原子性。表示组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有的操作执行成功,整个事务才提交。事务中的任何一个数据库操作失败,已经执行的任何操作都必须被撤销,让数据库返回初始状态。
  • C 表示Consistency,即一致性。事务操作成功后,数据库所处的状态和他的业务规则是一致的,即数据不会被破坏。如A账户转账100元到B账户,不管操作成功与否,A和B账户的存款总额是不变的。数据库事务在实现了另外三个原则的情况下,一致性就已经实现了。业务的一致性需要开发者决定。
  • I 表示Isolation,即隔离性。在并发数据操作时,不同的事务拥有各自的数据空间,他们的操作不会对对方产生干扰。准确地说,并非要求做到完全无干扰。数据库规定了多种事务隔离界别,不同的隔离级别对应不用的干扰程度,隔离级别越高,数据一致性越好,但并发性越弱。
  • D 表示Durability,即持久性。一旦事务提交成功后,事务中所有的数据操作都必须被持久化到数据库中。即使在事务提交后,数据库马上崩溃,在数据库重启时,也必须保证能够通过某种机制恢复数据,例如事务日志恢复。

隔离不好容易造成的问题

脏读

脏读指一个事务读到了另一个事务的中间结果,还用转账举例:

aa870977225474efe065162b1ecb5545.png

当A给B转账的事务没有执行完,另一个事务就读取了它的中间结果,就有可能造成脏读。因为万一之前的事务回滚,那么新读取到的结果就是错的,和A账号回滚之后的余额就不一致了。

不可重复读

不可重复读的意思是说,在一个事务中,我们读取了某个数据两次。刚好在这两次中间,有另一个事务修改了这条数据,那么同样会引起数据错误,因为这两次读取到的结果不一致。

527f03df5f59dd651adc1b9a298406d6.png

比如我们对A账户的一个事务还没有结束,这时它的结果就被另一个事务修改了,那么程序就会发生错乱,因为读到了它没有预料到的修改。

解决方法就是针对当前修改的数据进行隔离,同一时刻只允许一个事务对该条数据进行修改,以保证数据的一致性。

幻读

幻读就是一个事务读取两次,读到的数据条数不一致。这点和不可重复读非常类似,不过不同的是不可重复读是确定的某一条数据,而幻读是指整个数据库或者整个表而言。

3940e1f57f1a35018efb73b21f326158.png

要解决也很简单,因为幻读是其他事务修改其他数据产生的,所以要排除掉这种情况,只针对我们修改的数据进行加锁和隔离是不够的,我们需要将整个数据库,或者是分区进行隔离,同一时刻,只允许一个事务对一个分片或数据库表进行修改。

更新丢失

更新丢失的定义很直观,当我们修改一条数据的时候,另一个事务也在修改这条数据,导致后者的修改覆盖了前者修改的内容。

cb445fa6b4e8a420a226bf6d301dd98b.png

解决的办法是做好隔离操作,在一个事务写入完成之前,禁止其他事务写入。即更新丢失是在并发场景下出现的错误。

四种隔离级别

隔离级别 脏读 更新丢失 不可重复读 幻读 并发模型 更新冲突检测
未提交读 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 的默认隔离级别。
  • 可重复读:读取过程和已提交读级别一样,但在读取时会保持共享锁,直到事务结束。跟已提交读不同的是,只要一个事务没有结束,锁就不会释放,其他事务无法更新数据,保证了不会出现不可重复读。
  • 可串行读:在事务进行中,不仅会锁定受影响的数据本身,还会锁定整个范围。这就阻止了其他事务影响整体的情况出现。

Search

    Table of Contents