一、概念
什么是事务
数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。
当事务被提交给了DBMS(数据库管理系统),则DBMS需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库中,如果事务中有的操作没有成功完成,则事务中的所有操作都需要被回滚,回到事务执行前的状态;同时,该事务对数据库或者其他事务的执行无影响,所有的事务都好像在独立的运行。为什么需要事务
a.为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
b.当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。事务的4个特性--ACID
原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。
二、MySQL事务
2.1 事务类型
该部分引用自说说MySQL中的事务
-
扁平事务
扁平事务是最简单的一种,也是实际开发中使用的最多的一种事务。在这种事务中,所有操作都处于同一层次,最常见的方式如下:
BEGIN WORK
Operation 1
Operation 2
Operation 3
...
Operation N
COMMIT WORK
或者是这种:
BEGIN WORK
Operation 1
Operation 2
Operation 3
...
Operation N
(Error Occured)
ROLLBACK WORK
扁平事务的主要缺点是不能提交或回滚事务的某一部分,或者分几个独立的步骤去提交。
带有保存点的扁平事务
这种事务除了支持扁平事务支持的操作外,允许在事务执行过程中回滚到同一事务中较早的一个状态,这是因为可能某些事务在执行过程中出现的错误并不会对所有的操作都无效,放弃整个事务不合乎要求,开销也太大。保存点用来通知系统应该记住事务当前的状态,以便以后发生错误时,事务能回到该状态。链事务
链事务,就是指回滚时,只能恢复到最近一个保存点;而带有保存点的扁平事务则可以回滚到任意正确的保存点。嵌套事务
在事务中再嵌套事务,位于根节点的事务称为顶层事务。事务的前驱称为父事务,其它事务称为子事务。事务的前驱称为父事务,事务的下一层称为子事务。
子事务既可以提交也可以回滚,但是它的提交操作并不马上生效,除非由其父事务提交。因此就可以确定,任何子事务都在顶层事务提交后才真正的被提交了。同理,任意一个事务的回滚都会引起它的所有子事务一同回滚。
BEGIN WORK
SubTransaction1:
BEGIN WORK
SubOperationX
COMMIT WORK
SubTransaction2:
BEGIN WORK
SubOperationY
COMMIT WORK
...
SubTransactionN:
BEGIN WORK
SubOperationN
COMMIT WORK
COMMIT WORK
-
分布式事务
分布式事务通常是指在一个分布式环境下运行的扁平事务,因此需要根据数据所在位置访问网络中的不同节点
2.2 使用事务
-
事务设置
在MySQL命令行的默认设置下,事务都是自动提交的,即执行SQL语句后就会马上执行COMMIT操作。
mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | ON |
+---------------+-------+
1 row in set
因此要显示地开启一个事务须使用命令BEGIN
或START TRANSACTION
,或者执行命令SET AUTOCOMMIT=0
,用来禁止使用当前会话的自动提交。
mysql> SET AUTOCOMMIT=0;
Query OK, 0 rows affected
mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | OFF |
+---------------+-------+
1 row in set
另外,对于常见的两种存储引擎,InnoDB支持事务,MyISAM不支持。
事务控制语句
BEGIN
或START TRANSACTION
:显示地开启一个事务;COMMIT
或COMMIT WORK
:提交事务,并使已对数据库进行的所有修改成为永久性的;ROLLBACK
或ROLLBACK WORK
:回滚,结束用户的事务,并撤销正在进行的所有未提交的修改;SAVEPOINT identifier
:在事务中创建一个保存点,一个事务中可以有多个保存点;RELEASE SAVEPOINT identifier
:删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;ROLLBACK TO identifier
:把事务回滚到标记点;SET TRANSACTION
:设置事务的隔离级别。InnoDB存储引擎提供事务的隔离级别有READ UNCOMMITTED
、READ COMMITTED
、REPEATABLE READ
和SERIALIZABLE
。
2.3 事务隔离级别
先看一个表格总结:
隔离级别 | 脏读(Dirty Read) | 不可重复读(NonRepeatable Read) | 幻读(Phantom Read) |
---|---|---|---|
未提交读:Read uncommitted | yes | yes | yes |
已提交读:Read committed | no | yes | yes |
可重复读:Repeatable read | no | no | yes |
可串行化:Serializable | no | no | no |
注:yes只是指有可能,并不一定会发生;no是指绝对不会发生。
再看具体释义:
未提交读:Read uncommitted
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。
本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。已提交读:Read committed
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理期间可能会有新的commit,所以同一select可能返回不同结果。可重复读:Repeatable read
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。可串行化:Serializable
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
一些概念补充
-
脏读(Drity Read)
某个事务已更新一份数据(但还未提交),另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的,脏的。 -
不可重复读(Non-repeatable read)
在一个事务的两次查询之中数据不一致,即同一事务中,同样的条件 , 读取过的数据 , 再次读取出来发现值不一样了。这可能是两次查询过程中间插入了一个事务更新的原有的数据。 -
幻读(Phantom Read)
在一个事务的两次查询中数据不一致。重点在于新增或者删除:同样的条件 , 第 1 次和第 2 次读出来的记录数不一样。例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。
更新
20180116--细化幻读和不可重复读的概念区分