数据库事务ACID

下面是从网上整理来的:

原子性

无论一个事务里有多少执行步骤,这所有的步骤合起来是一个最小的执行单元,要么不做,要么全做,不存在只做到一半情况。比如银行转账,转出跟转入这两个包含在一个事务里的动作就是原子的。要么不转出也不转入,转出了就要转入。

一致性

事务执行前与执行后数据内在的逻辑始终是成立的。比如转账前与转账后两人存款的总和始终不变。

隔离性

虽说事务是原子的,要么不做,要么全做,不存在做一半的情况。但是从代码实现上来说,事务里的步骤还是一步一步执行的,还是存在事务做到一半的情况。比如转账,代码怎么写?就两行代码,是先转出扣钱,再转入加钱。两行代码中间,也就是转出之后,转入之前,此时数据是不一致的。那怎样始终保证数据一致?那就用一个类似自欺欺人的办法,让转账这个事务在完成之前对别人都不可见,事务完成之前别人看到的都是转账前的状态,看不到转账步骤中间不一致的状态,所谓”隔离”。

实际中,一个事务会不会读取到另一个未提交的事务修改的数据,这个就是互相影响的程度。在事务并发操作时,可能出现的问题有:

  1. 脏读:事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。
  2. 不可重复读:在同一个事务中,对于同一份数据读取到的结果不一致。比如,事务B在事务A提交前读到的结果,和提交后读到的结果可能不同。不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这回导致锁竞争加剧,影响性能。另一种方法是通过MVCC可以在无锁的情况下,避免不可重复读。
  3. 幻读:在同一个事务中,同一个查询多次返回的结果不一致。事务A新增了一条记录,事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。 ~幻读是由于并发事务增加记录导致的~ ,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。需要将事务串行化,才能避免幻读。

事务的隔离级别从低到高有:

  1. Read Uncommitted:最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
  2. Read Committed:只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。
  3. Repeated Read:在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。
  4. Serialization:事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。通常,在工程实践中,为了性能的考虑会对隔离性进行折中。

持久性

事务做完了就是做完了,就生效了。就像钱转给别人后当前这比转账交易就结束了,不可能再倒回来。

如何理解数据库事务中的一致性的概念? - 知乎

11-19 14:23