数据库事务的基本概念
事务(Transaction)是并发控制的基本单位。所谓的事务,可以看做一个操作序列,这一操作序列里面所包含的所有操作要么都执行,要么都不执行,它是一个不可分割的工作单位。
在银行转账的过程中,需要从一个账户的钱款转移到另外一个账户上,这样必定涉及一删一增的操作。在没有事务的情况下,假设在完成对甲方账户扣款,由于不可控力,数据在进行下一步操作时失败或丢失,这样乙方账户就正常无法收到这笔欠款,且甲方已扣除欠款而无法退还。但在存在事务的情况下,由于事务的特性,当在转账过程中出现异常,就会立即回滚,保证甲乙两方账户的安全。
事务具有以下4个基本特性:
- 原子性(Atomicity)事务中包含的操作被看做一个逻辑单元,这个逻辑单元中的操作要么全部成功,要么全部失败。
- 一致性(Consistency)一个事务的执行前后,数据库都必须处于数据一致性状态。
- 隔离性(Isolation)事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正确性和完整性。同时,并行事务的修改必须与其他并行事务的修改相互独立。
- 持久性(Durability)事务结束后,对数据库中数据的影响是永久的。
事务的基本SQL语句
1 | START TRANSACTION; -- 开启事务 |
1 | -- 转账小例子 |
事务的并发执行
在数据库系统中,如果各个事务都是按串行方式执行的,DBMS很容易实现事务的ACID特性。这是因为在DBMS中串行执行事务程序,不会导致数据不一致性和事务隔离性问题。但是,在实际应用中,需要在DBMS中多个事务并发执行,原因如下:
- 改善系统的资源利用率。一个事务一般都是由多个操作组合而成的,它们在不同执行阶段需要不同的资源。有时需要I/O资源,有时需要CPU资源或需要网络资源。如果事务能够并发执行的话,就能够充分利用系统资源,提高系统处理的吞吐能力。
- 减少事务运行的平均时间。每个事务的执行时长不同,倘若事务是串行处理的,那么当有些需要长时间处理的事务必定阻塞只需短时间处理的事务。所以事务的并发执行是刚需。
并发执行产生的后果
事务并发执行倘若不加约束的话,不但效率不会增加,反而不如串行执行,主要表现在若干数据的不一致问题,如脏读、不可重复读、幻读、丢失更新等问题。
- 脏读(Dirty Read)
脏读是指当一个事务读取被另外一个事务所修改的共享数据后,若修改数据的事务因某种原因失败,数据未被提交到数据库中,而读取共享数据的事务则在同一时刻,获取一个垃圾数据,即脏数据。
脏数据是对未提交事务中所修改的数据的统称。如果别的事务读取了这个数据,则可能会导致应用的数据错误,也造成不同应用的数据不一致问题。
-
图中,事务A和事务B共享访问雇员表信息。其中事务B将雇员编号为1的年龄数据从18修改为20。在事务A结束前,事务A程序再次读取了该雇员信息,获得了新的年龄数据20。但事务B在结束前,由于某种原因,回滚了之前的操作数据,即雇员编号为1的年龄数据恢复到18,从而导致事务A获取了一个脏数据。
- 不可重复读(Unrepeatable Read)
不可重复读是指当一个事务对同一共享数据重复读取两次,但是发现原有的数据改变或丢失。这是由于多个事务并发执行时,其中一个事务对共享数据执行了修改或删除操作造成的。
-
图中,事务A和事务B共享访问雇员表信息。事务A第一次读取雇员年龄数据小于或等于20的数据为3条。其后事务B将雇员编号为2的数据删除。当事务A再次读取雇员年龄数据小于或等于20的数据时,则为2条。
- 幻读(Phantom Read)
幻读是指当一个事务对同一个共享数据重复读取两次,但是发现第二次读取比第一次读取时,新增了一些数据。这是由于多个事务并发执行时,其中一个事务同时对共享数据进行添加操作造成的。
-
图中,事务A和事务B共享访问雇员表信息。事务A第一次读取雇员年龄数据小于或等于20的数据为2条。其后事务B新添加了雇员编号为3的数据。当事务A再次读取雇员年龄数据小于或等于20的数据时,则为3条。
- 丢失更新(Lost Update)
丢失更新是指一个事务对一共享数据进行更新处理,但是以后再查询该共享数据值与原更新值不一致。这是由于多个事务并发执行,其中一个事务也对同一个共享数据进行了更新,并将前面事务的更新值改变了。
-
图中,事务A和事务B共享访问雇员表信息。事务A对雇员编号为1的年龄数据修改为19。其后事务B也对该雇员的年龄数据进行修改,数据改为20。当事务A再次读取该雇员的信息时,其年龄数据已与先前数据修改不同。
事务隔离级别
为了避免事务并发执行可能出现的以上的并发问题而导致的数据不一致问题,可以在DBMS中设置事务隔离级别(Isolation Level)。
各个隔离级别解释:
- 读取为提交(READ UNCOMMITED)。指定语句可以读取已由事务修改但尚未修改的行。
- 读取已提交(READ COMMITED)。指定语句不能读取已由其他事务修改但尚未提交的数据。
- 可重复读(REPEATABLE READ)。指定语句不能读取已由其他事务修改但尚未提交的行,并且指定,其他任何事务都不能在当前事务完成之前修改由当前事务修改的数据。
- 可串行化(SERIALIZABLE)。指定事务中任何语句所读取的数据都将是在该事务开始时便存在的数据。 所有事务都是按顺序执行。
数据库锁机制
// 有空再写笔记补充
参考资料:
[1] http://blog.csdn.net/zdwzzu2006/article/details/5947062
[2] http://www.cnblogs.com/Achang/archive/2013/03/22/2975161.html