事务是访问并更新数据库中各种数据项的一个程序执行单元。在事务中的操作,要么都执行修改,要么都不执行,这就是事务的目的,也是事务模型区别于文件系统的重要特征之一。
严格上来说,事务必须同时满足4个特性,即通常所说事务的ACID特性。虽然理论上定义了严格的事务要求,但是数据库厂商出于各种目的并没有严格满足事务的ACID标准。例如,对于MYSQL的NDB Cluster引擎,虽然支持事务,但是不满足D的要求,即持久性的要求。对于Oracle数据库来说,其默认的事务隔离级别为READ COMMITTED,不满足I的要求,即隔离性的要求。对于InnoDB存储引擎而言,默认的事务隔离级别是READ REPRATABLE,完全遵循和满足事务的ACID特性。
A(atomicity),原子性。原子性指整个数据库事务是不可分割的工作单位。只有使事务中所有的数据库操作都执行成功,整个事务的执行才算成功。事务中任何一个SQL语句执行失败,那么已经执行成功的SQL语句也必须撤销,数据库状态应该退回到事务前的状态。
C(consistency),一致性。一致性是指事务将数据库从一种状态转变为另一种状态。在事务的开始之前和事务结束以后,数据库的完整性约束没有被破坏。
I(isolation),隔离性。隔离性还有其他的称呼,如并发控制、可串行化、锁。事务的隔离性要求每个读写事务的对象与其他事务的操作对象能互相分离,即该事务提交前对其他事务都不可见,这通常使用锁来实现。数据库系统中提供了一种粒度锁的策略,允许事务仅锁住一个实体对象的子集,以此来提高事务之间的并发度。(如果是全表锁,事务之间基本就无法实现并发,但是如果只锁住表中处理的行,可以提高事务的并发度)
D(durability),持久性。事务一旦提交,其结果就是永久性的。即使发生宕机等故障,数据库也能将数据恢复。需要注意的是,持久性只能从事务本身的角度来保证结果的永久性,如事务提交后,所有的变化都是永久的,即使当数据库由于崩溃而需要恢复时,也能保证恢复后提交的数据都不会丢失。
事务的(ACID)特性是由关系数据库管理系统(RDBMS,数据库系统)来实现的。数据库管理系统采用日志来保证事务的原子性、一致性和持久性。日志记录了事务对数据库所做的更新,如果某个事务在执行过程中发生错误,就可以根据日志,撤销事务对数据库已做的更新,使数据库退回到执行事务前的初始状态。数据库管理系统采用锁机制来实现事务的隔离性。当多个事务同时更新数据库中相同的数据时,只允许持有锁的事务能更新该数据,其他事务必须等待,直到前一个事务释放了锁,其他事务才有机会更新该数据。
事务分类
- 扁平事务,最简单,使用最频繁的事务。在扁平事务中,所有的操作都处于一个层次,其有BEGIN WORK开始,有COMMIT WORK或ROLLBACK WORK结束。处于之间的操作是原子的,要么全部执行,要么全部回滚。
- 带有保存点的扁平事务,除了扁平事务支持的操作外,允许在事务执行过程中回滚到同一事务中较早的一个状态,这是因为可能有些事务在执行过程中出现的错误并不会对有的操作都无效,放弃整个事务不合乎要求,开销也太大。保存点用来通知系统应该记住事务当前的状态,以便以后发生错误时,事务能回到该状态。
- 链事务可视为保存点模式的一个变种。
- 嵌套事务是一个层次结构框架。
- 分布式事务
事务控制语句
在MYSQL命令行的默认设置下,事务都是自动提交的,即执行SQL语句后就会马上执行COMMIT操作。因此要显示的开启一个事务必须使用命令BEGIN和START TRANSACTION,或者执行命令SET AUTOCOMMIT = 0,以禁用当前会话的自动提交。事务控制语句如下:
- START TRANSACTION | BEGIN:显示的开启一个事务。在存储过程中,MYSQL数据库的分析器会自动将BEGIN识别为BEGIN...END,因此在存储过程中只能使用START TRANSACTION语句来开启一个事务。
- COMMIT:要想使用这个语句的最简形式,只需发出COMMIT。COMMIT会提交事务,并使已对数据库进行的所有修改成为永久性的。COMMIT和COMMIT WORK语句基本上是一致的,都是用来提交事务。不同的是COMMIT WORK用来控制事务结束后的行为是CHAIN还是RELEASE的。如果是CHAIN方式,那么事务就变成了链事务。用户可以通过参数completion_type来进行控制,默认该参数是0,表示没有任何操作。在这种设置下,COMMIT和COMMIT WORK是完全等价的。当参数值为1时,COMMIT WORK等价于COMMIT AND CHAIN,表示马上自动开启一个相同隔离级别的事务。当参数值为1时,COMMIT WORK等价于COMMIT AND RELEASE。当提交事务后会自动断开与服务器连接。
- ROLLBACK:回滚会结束用户的事务,并撤销正在进行的所有未提交的修改。
- SAVEPOINT identifiter:SAVEPOINT允许用户在事务中创建一个保存点,一个事务可以有很多个保存点。
- RELEASE SAVEPOINT identifier:删除一个事务的保存点,当没有一个保存点执行这语句时,会抛出一个异常。
- ROLLBACK to [SAVEPOINT] identifier:这个语句与SAVEPOINT命令一起使用。可以把事务回滚到标记点,而不回滚到此标记点之前的任何工作。注意:虽然有ROLLBACK,但是它并没有真正的结束一个事务,因此即使执行了ROLLBACK TO SAVEPOINT,之后也需要显示的运行COMMIT或ROLLBACK命令。
- SET TRANSACTION:这个语句用来设置事务的隔离级别。InnoDB存储引擎提供的事务隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。
事务的隔离级别
ANSI SQL标准定义的四个隔离级别为:
- READ UNCOMMITTED(未提交读),事务中的修改,即使没有提交,在其他事务也都是可见的。事务可以读取未提交的数据,这也被称为脏读。
- READ COMMITTED(提交读),一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。这个级别有时候也叫做不可重复读,因为两次执行相同的查询,可能会得到不一样的结果。因为在这2次读之间可能有其他事务更改这个数据,每次读到的数据都是已经提交的。
- REPEATABLE READ(可重复读),解决了脏读,也保证了在同一个事务中多次读取同样记录的结果是一致的。但是理论上,可重读读隔离级别还是无法解决另外一个幻读的问题,指的是当某个事务在读取某个范围内的记录时,另外一个事务也在该范围内插入了新的记录,当之前的事务再次读取该范围内的记录时,会产生幻行。
- SERIALIZABLE(可串行化),它通过强制事务串行执行,避免了前面说的幻读的问题。
1、脏读(dirty read):一个事务可以读取另一个尚未提交事务的修改数据。
2、不可重复读(nonrepeatable read):在同一个事务中,同一个查询在T1时间读取某一行,在T2时间重新读取这一行时候,这一行的数据已经发生修改,可能被更新了(update),也可能被删除了(delete)。
3、幻像读(phantom read):在同一事务中,同一查询多次进行时候,由于其他插入操作(insert)的事务提交,导致每次返回不同的结果集。
InnoDB采用MVCC来支持高并发,并实现了四个标准的隔离级别。其默认级别是REPEATABLE READ(可重复读),并且通过间隙锁(next-key locking)策略防止幻读的出现。间隙锁使得InnoDB不仅仅锁定查询涉及的行,还会对索引中的间隙进行锁定,以防止幻影的插入。
隔离级别越低,事务请求的锁越少或保持锁的时间就越短。所以很多数据库系统默认的事务隔离级别是READ COMMITTED。质疑SERIALIZABLE隔离级别的性能,但是InnoDB存储引擎认为两者的开销是一样的,所以默认隔离级别使用REPEATABLE READ。
用命令设置当前会话或全局会话的事务隔离级别。
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL
{
READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE
}
如果想启动时就设置事务的默认隔离级别,修改MYSQL的配置文件,在[mysqld]中添加如下行:
[mysqld]
transaction-isolation = READ-COMMITTED
分布式事务编程
InnoDB存储引擎提供了对于XA事务的支持,并通过XA事务来支持分布式事务的实现。分布式事务指的是允许多个独立的事务资源参与到一个全局的事务中。事务资源通常是关系型数据库系统,也可以是其他类型的资源。全局事务要求在其中的所有参与的事务要么都提交,要么都回滚,这对于事务的ACID要求又有了提高。在使用分布式事务时,InnoDB存储引擎的事务隔离级别必须设置成SERIALIZALE。
XA事务由一个或多个资源管理器、一个事务管理器、以及一个应用程序组成。
- 资源管理器:提供访问事务资源的方法。通常一个数据库就是一个资源管理器。
- 事务管理器:协调参与全局事务中的各个事务。需要和参与到全局事务中的所有资源管理器进行通信。
- 应用程序:定义事务的边界,指定全局事务中的操作。
在MYSQL数据库的分布式事务中,资源管理器就是MYSQL数据库,事务管理器为连接到MYSQL服务器的客户端。
分布式事务使用两段式提交(two-phase commit)的方式。在第一阶段,所有参与全局事务的节点都会开始准备(PREPARE),告诉事务管理器他们准备好了。第二阶段,事务管理器告诉资源管理器执行ROLLBACK或COMMIT。如果任何一个节点显示不能提交,则所有的节点都会被告知需要回滚。与本地事务不同的是,需要多一次的PREPARE操作,待收到所有节点的同意信息后,再进行COMMIT或ROLLBACK操作。
转载请注明出处。
作者:wuxiwei
出处:http://www.cnblogs.com/wxw16/p/6128582.html