事务的特性

事务可以理解成一组对数据库的操作,而这一组操作满足一定的特性,所以被称为事务。事务有4个特性,简称ACID。

A:原子性

一个事务要么全部执行成功提交,要么全部失败回滚,不存在只成功执行事务中的一部分操作,而有些操作没被执行。即事务中的所有操作是不可分割的,这就是事务的原子性。

C:一致性

一个事务的执行不能破坏数据库的一致性。一个事务在执行之前和执行之后,数据库都必须处于一致性状态。
根据上述的定义实际上对于一致性的理解是很模糊的。数据库的一致性指的是数据库处于“正确的状态”。也就是事务的一致性是保证数据库必须从一个正确的状态到另一个正确的状态。
但是“正确的状态”应该是由用户定义的,例如在如果数据库中出现了余额小于0的记录,我们说数据库不一致了,但显然这种一致性是用户定义的,也就是应用层的东西。因此事务技术本身并不能保证数据库的一致性,所以正确来说应该是用户根据事务技术的AID特性,可以实现数据库的一致性,让数据库保持在用户要求的正确的状态。
举个例子:

A要向B支付100元,而A的账户中只有90元,我们的账户余额列没有任何约束。但是我们业务上不允许账户余额小于0。因此支付完成后我们会检查A的账户余额,发现余额小于0了,于是我们进行了事务的回滚。

上述例子中我们使用了事务来保持了数据库的一致性,或者说是应用层利用事务回滚保证了业务的约束不被破坏。
再举个例子:

A要向B支付100元,而A的账户中只有90元,账户的余额列没有任何约束。然后支付成功了。A的余额为-10。

上例中事务提交后产生了数据库不一致的状态,因为事务执行前和执行后,我们的系统没有任何的约束被破坏。一直都是保持在正确的状态,但我们的业务不允许这样的数据出现。
所以到了这里我们总结:数据库一致性是用户(应用层)定义的,所以对于事务技术本身而言不能保证数据库的一致性。但是我们回顾事务一致性的定义:“一个事务在执行之前和执行之后,数据库都必须处于一致性状态”,是指用户利用事务的AID其他三个特性,在应用层上保证事务执行前后数据库都保持在了一致的状态,从而满足事务的一致性。因此AID是过程,C是结果

I:隔离性

在多个事务并发时,一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能相互干扰。隔离性是一种理论,不是一种具体的技术,这么说的原因是:1. 事务之间的隔离有不同程度的隔离,这也就是下文要讲的事务的隔离级别。2. 只要满足相应隔离级别的要求,实现方式是多样的。并非一定要给事务一个独立的数据空间才能达到相应隔离级别的目标。

D:持久性

持久性指一旦事务成功提交,那么它对数据库中的对应数据的状态的变更就会永久保存到数据库中。即使发生系统崩溃或机器宕机等故障,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束的状态。

事务的隔离级别

了解事务的隔离级别之前我们需要先了解脏写、脏读、不可重复读、幻读
事务的隔离级别是一种理论或者定义,而不是具体的技术。通过实现事务不同的隔离级别我们能不同程度地避免上述脏读、不可重复读等中的一个或多个。

Read uncommitted(读未提交)

如果一个事务已经开始写数据,则另外一个事务不允许同时进行写操作。但允许其他事务读此行数据,该隔离级别可以通过在写时加锁,排斥其他线程写操作、但不排斥读线程实现。
总结:不可以写未提交的数据,可以读未提交的数据,即:避免了脏写,可能出现脏读

Read committed(读提交)

如果是一个读事务(线程),则允许其他事务读+写;如果是写事务则禁止其他的读+写事务访问该行数据,也可以通过加锁实现。
总结:只可以读、写提交了的数据,即:避免了脏写、脏读,但是可能出现不可重复读

Repeatable read(可重复读)

可重复读是指在一个事务内,多次读同一个数据,在这个事务还没结束时,其他事务不能写该数据;而写事务则禁止任何其他事务访问,从而保证同一个事务内两次读到的数据一致。
总结:当一个事务读一条数据,保证在事务结束前再次读也是得到一样的结果,即:避免了脏写、脏读、不可重复读,但可能出现幻读

Serializable(可序化)

最严格的事务隔离,它要求事务序列化执行,即只能一个接着一个地执行,但不能并发执行。仅仅通过“行级锁”是无法实现序列化的,必须通过其他机制保证新插入的数据不会被执行查询操作的事务访问到。
总结:事务串行执行,可以避免脏写、脏读、不可重复读、幻读,但效率低、性能差

参考

https://blog.csdn.net/zhouym_/article/details/90381606
https://www.zhihu.com/question/31346392
https://www.jianshu.com/p/fc8a654f2205