事务具有四大特征,分别是原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),简称为事务的ACID特性。
原子性(Atomicity)
原子性是指事务必须是一个原子的操作序列单元。事务中包含的各项操作在一次执行过程中,只允许出现以下两种状态之一。
- 全部成功执行
- 全部不执行
任何一项操作失败都将导致整个事务失败,同时其他已经被执行的操作都将被撤消并回滚,只有所有的操作全部成功,整个事务才算是成功完成。
一致性(Consistency)
一致性是指事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态。也就是说事务的执行结果必须是使数据库从一个一致性状态转变到另一个一致性状态。因此当事务全部成功提交时,就能说数据库处于一致性状态,如果数据库运行过程中出现故障,导致有些事务尚未完成就被迫中断,这些未完成的事务中的部分操作已经写入的物理数据库,这时数据库就处于一种不一致的状态。
隔离性(Isolation)
隔离性是指在并发环境中,并发的事务是相互隔离的,一个事务的执行不能被其它事务干扰。也就是说,不同的事务并发操作相同的数据时,每个事务都有各自完整的数据空间,即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
在标准的SQL规范中,定义了四个事务隔离级别,不同的隔离级别对事务的处理不同
- 未授权读取
也称读未提交(Read Uncommitted),该隔离级别允许脏读,隔离级别最低。
什么是脏读?
如果一个事务正在处理某一数据,对其进行了更新,但尚未提交事务,与此同时,另一个事务能够访问该事务更新后的数据。也就是说,事务的中间状态对其它事务是可见的。
举例说明:
用户A原工资为1000元
第一步:事务1执行修改操作,为用户A增加工资1000元,事务1尚未提交事务
第二步:事务2执行读取操作,查询到用户A的工资为2000元。
事务2读取到了事务1中尚未提交的修改结果,但是事务1尚未提交,有可能会因为后续操作失败而产生回滚。
- 授权读取
也称读已提交(Read Committed),该隔离级别禁止脏读,允许不可重复读。
什么是不可重复读?
一个事务过程中,对同一数据进行多次查询,查询的数据可能不一样,原因可能是两次查询过程中,另一个事务对该数据进行了修改并成功提交事务。也就是说,事务的结束状态对其它事务是可见的。
举例说明:
用户A原工资为1000元
第一步:事务1执行查询操作,查询到用户A的工资为1000元,事务1尚未提交事务。
第二步:事务2执行修改操作,为用户A的增加工资1000元。
第三步:事务1执行查询操作,查询到用户A的工资为2000元。
对于事务1来说,同一个事务里的多次查询,结果并不稳定。
- 可重复读取
可重复读取(Repeatable Read),该隔离级别禁止不可重复读和脏读,允许幻读。保证在事务处理过程中,多次读取同一数据,其值都和事务开始时刻是一致的。
什么是幻读?
不可重复读针对的是数据的修改,而幻读针对的是数据的新增。
举例说明:
用户表,用户名为唯一键
第一步:事务1执行查询操作,查询是否存在用户名为aaa
的数据,事务1尚未提交
select 1 from user where username = 'aaa'
第二步:事务2执行插入操作,插入用户名为aaa
的数据
第三步:事务1执行插入操作,插入用户为为aaa
的数据,提示唯一键错误,插入失败。
对于事务一来说,查询用户aaa
不存在,保存却报唯一键错误,如梦如幻,故名幻读。
- 串行化
串行化(Serializable)是最严格的事务隔离级别,它要求所有事务都被串行执行,即事务只能一个一个地进行处理,不能并发执行。
mysql 默认使用 Repeatable Read 级别,其它数据库大部分默认使用 Read Committed 级别
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
未授权读取 | 存在 | 存在 | 存在 |
授权读取 | 不存在 | 存在 | 存在 |
可重复读取 | 不存在 | 不存在 | 存在 |
串行化 | 不存在 | 不存在 | 不存在 |
持久性(Durability)
持久性是指一个事务一旦提交,它对数据库中对应数据的状态变更就应该是永久性的。也就是说,它对数据库所做的更新就必须被永久保存一下,即使发生系统崩溃或机器宕机等故障,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束时的状态。