1. 事务的概念
事务(Transaction)是一个操作序列。这么操作要么都做,要么都不做,是一个不可分割的工作单位。事务通常以BEGIN TRANSACTION
开始,以COMMIT
或ROLLBACK
操作结束:COMMIT
表示提交事务中的所有操作,事务正常结束;ROLLBACK
表示回滚,即撤销已做的所有操作,回滚到事务开始时的状态。
2. 事务的四个特性(ACID)
2.1 原子性(Atomicity)
原子性是指事务在逻辑上是不可分割的操作单元,其所有语句要么都执行,要么都撤销执行。当每个事务运行结束时,可以选择“提交”所做的数据修改,并将这些修改永久应用到数据库中。
示例:假设有A和B两个账户,A账户转给B账户500元,这里面包含有两个动作:1)A账户减去500元,2)B账户增加500元,这两个动作不可分割即原子性。
2.2 一致性(Consistency)
一个事务就是一系列在逻辑上相关的操作指令的集合,用于完成一项任务,事务执行的结果(本质)是将数据库中的数据从一种一致性状态转换到另一种一致性状态,以体现现实世界中的状况变化。
示例:假设账户A和账户B两者的钱加起来总金额是6000元,那么不管A和B之间如何转账、转几次账,事务结束后两个账户的钱相加起来还是6000元,这就是事务的一致性。
2.3 隔离性(Isolation)
隔离性是针对并发事务而言的,所谓并发是指数据库服务器同时处理多个事务,如果不采取专门的控制机制,那么并发事务之间可能会相互干扰,进而导致数据出现不一致或错误的状态。隔离性就是要隔离并发运行的多个事务间的相互影响,即保证一个事务的执行不受其他事务的干扰。
示例:隔离性即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
2.4 持久性(Durability)
持久性(也称永久性)是指一旦事务提交成功,其对数据的修改是永久性的,不能回滚。
示例:当开发人员在使用JDBC操作数据库是,在提交事务后,提示用户事务操作完成,那么这个时候数据就已经存储在磁盘上了。即使数据库重启,该事务所做的更改操作也不会丢失。
3. 事务的分类
从事务理论的角度来看,事务可以分为以下几种类型:
3.1 扁平事务(Flat Transactions)
扁平事务虽然是最简单的事务类型,但却是实际中使用最频繁的事务。在扁平事务中,所有操作都处于统一层次,其由BEGIN WORK
开始,由COMMIT WORK
或ROLLBACK WORK
结束,其间的操作是原子的,要么都执行,要么都回滚。扁平事务是应用程序成为原子操作的基本组成模块,其只要限制是不能提交或者回滚事务的某一部分,或分几个步骤提交。
扁平事务一般有三种不同的结果:1)事务成功完成,约占所有事务的96%;2)应用程序要求停止事务,如应用程序捕获到异常时会回滚事务,约占所有事务的3%;3)外界因素强制终止事务,如连接超时或连接断开,约占所有事务的1%。
3.2 带有保存点的扁平事务(Flat Transactions with Savepoints)
保存点(Savepoint)用来通知事务系统应该记住事务当前的状态,以便未来发生错误后事务能回到保存点当时的状态。带有保存点的扁平事务除了支持扁平事务支持的操作外,还允许在事务执行过程中回滚到同一事务中较早的一个状态。这是因为某些事务可能在执行过程中出现的错误并不会导致所有的操作都无效,所以放弃整个事务不合乎要求,开销太大。
3.3 链事务(Chained Transactions)
链事务是指一个事务有多个子事务链式组成,它可以被视为保存点模式的一个变种。链事务的思想是:在提交一个事务时,释放不需要的数据对象,将必要的处理上下文隐式地传给下一个要开始的事务,前一个子事务的提交操作和下一个子事务的开始操作合并为一个原子操作,这意味着下一个事务将看到上一个事务的结果,就好像在一个事务中进行一样。这样的好处在于,在提交子事务时就可以释放不需要的数据对象,而不必等到整个事务完成后才释放。
链事务与带有保存点事务的不同之处体现在:
带有保存点的扁平事务 | 链事务 | |
---|---|---|
回滚 | 带有保存点的扁平事务能够回滚到任意正确的保存点 | 链事务中回滚仅限于当前事务,即只能恢复到最近的一个保存点 |
锁处理 | 带有保存点的扁平事务执行COMMIT 后不影响迄今为止所持有的锁 |
链事务在执行COMMIT 后即释放了当前所持有的锁 |
3.4 嵌套事务(Nested Transactions)
嵌套事务是一个层次结构框架,由一个顶层事务(Top-Level Transaction)控制着各个层次的事务,顶层事务之下嵌套的事务被称为子事务(Subtransaction),其控制着每一个局部的变换,子事务本身也可以是嵌套事务。因此,嵌套事务的层次结构可以看成是一棵树。
3.5 分布式事务(Distributed Transactions)
分布式事务通常是在一个分布式环境下运行的扁平事务,因此,需要根据数据所在位置访问网络中不同节点的数据库资源。例如,一个银行用户从招商银行的账户向工商银行的账户转账1000元,这里需要用到分布式事务,因为不能仅调用某一家银行的数据库就完成任务。
4. 事务的四种隔离级别
隔离级别比较:未提交读 < 已提交读 < 可重复读 < 可串行化
。不同的隔离级别有不同的现象,并有不同的锁和并发机制,隔离级别越高,数据库的并发性能就越差。
4.1 未提交读(Read Uncommitted)
在该隔离级别,所有事务都可以看到其他未提交的事务的执行结果,即在未提交读级别,事务中的修改,即使没有提交,对其他事务也都是可见的。读取未提交的数据,就是脏读。该隔离级别最低,并发性能最高,但在实际中很少应用。
4.2 已提交读(Read Committed)
这是大多数数据库系统的默认隔离级别。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。换句话说,一个事务从开始直到提交之后,所做的任何修改对其他事务都是不可见的。
4.3 可重复读(Repeatable Read)
可重复读可以确保同一个事务在多次读取同样行记录数据的时候,得到同样的结果。可重复读解决了脏读的问题,但在理论上会导致幻读的问题。
4.4 可串行化(Serializable)
这是最高的隔离级别,它通过强制事务排序,强制事务串行执行,使之不可能相互冲突,从而解决幻读的问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能出现大量的超时现象和锁竞争。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑使用该级别。这是花费代价最高但是最可靠的事务隔离级别。

5. 不考虑事务的隔离性会导致的问题
5.1 脏读(Dirty Read)
一个事务读取了已被另一个事务修改、但未提交的数据,脏读只在未提交读隔离级别才会出现。
5.2 不可重复读(Nonrepeatable Read)
在同一个事务中,同一个查询在Time1时刻读取某一行,在Time2时刻重新读取这一行数据的时候,发现这一行数据已经发生修改,可能被更新了(UPDATE),也可能被删除了(DELETE)。不可重复读在未提交读和已提交读隔离级别都可能会出现。
5.3 幻读(Phantom Read)
在同一事务中,当同一查询多次执行的时候,由于其他(满足该查询条件的)插入(INSERT)操作的事务提交,会导致每次返回不同的结果集。幻读是事务非独立执行时发生的一种现象。幻读在未提交读、已提交读、可重复读隔离级别都可能会出现。
区别对比 | 说明 |
---|---|
脏读和不可重复读 | 脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是在同一个事务范围内多次查询同一条数据却返回了不同是数据值。 |
幻读和不可重复读 | 幻读和不可重复读都是读取了另一个事务中已经提交的数据,不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一个数据整体。 |
6. Oracle、MySQL和SQL Server中的事物隔离级别比较
Oracle | MySQL | SQL Server | |
---|---|---|---|
支持 | Read Committed(已提交读) Serializable(可串行化) |
Read Uncommitted(未提交读) Read Committed(已提交读) Repeatable Read(可重复读) Serializable(可串行化) |
Read Uncommitted(未提交读) Read Committed(已提交读) Repeatable Read(可重复读)Serializable(可串行化) Snapshot(快照) Read Committed Snapshot(已提交读隔离) |
默认 | Read Committed(已提交读) | Repeatable Read(可重复读) | Read Committed(已提交读) |
设置语句 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; —已提交读SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; —可串行化 |
SET GLOBAL(SESSION) TRANSACTION ISOLATION LEVEL READ UNCOMMMITTED; —未提交读SET GLOBAL(SESSION) TRANSACTION ISOLATION LEVEL READ COMMMITTED; —已提交读 |
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; —可串行化ALTER DATABASE TEST SET ALLOW_SNAPSHOT_ISOLATION ON; —快照 |

...
...