数据库并发控制及SQL Server的
并发控制机制
在多用户和网络环境下,数据库是一个共享资源,多个用户或应用程序同时对数据库的同一数据对象进行读写操作,这种现象称为对数据库的并发操作。显然并发操作可以充分利用系统资源,提高系统效率。虽然如此,但是如果对并发操作不进行控制会造成一些错误。对并发操作进行的控制称为并发控制。并发控制机制是衡量一个DBMS的重要性能指标之一。
10.1 事务及并发控制的基本概念
10.1.1 事务的概念
所谓事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位。例如,在关系数据库中,一个事务可以是一条SQL语句、一组SQL语句或整个程序。事务和程序是两个概念。一般地讲,一个程序中包含多个事务。
事务的开始与结束可以由用户显式定义。如果用户没有显式地定义事务,则由DBMS按默认自动划分事务。在SQL语言中,定义事务的语句有三条:
BEGINTRANSACTION;
COMMIT;
ROLLBACK
事务通常是以BEGINTRANSACTION开始,以COMMIT或ROLLBACK结束。COMMIT的作用是提交,即提交事务的所有操作。事务提交是将事务中所有对数据的更新写回到磁盘上的物理数据库中去,事务正常结束。ROLLBACK的作用是回滚,即在事务运行的过程中发生了某种故障,事务不能继续执行,系统将事务中对数据库的所有已完成的操作全部撤消,回滚到事务开始时的状态。
10.1.2 事务的特性
事务具有4个特性,即原子性、一致性、隔离性和持续性。
1.原子性(Atomicity):事务中包括的诸操作要么都做,要么都不做。也就是说,事务是作为一个整体单位被处理,不可以被分割。
2.一致性(Consistency):事务执行的结果必须使数据库处于一个一致性状态。当数据库中只包含成功事务提交的结果时,就说数据库处于一致性状态。
如果数据库系统运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是不一致状态,数据库系统必须确保事务的一致性。
3.隔离性(1solation):一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
4.持续性(Durability)。持续性也称永久性(Permanence)。持续性指一个事务一旦提交,它对数据库中数据的改变就是永久性的,接下来的其他操作或故障不应该对其执行结果有任何影响。
事务的这些特性由数据库管理系统中并发控制机制和恢复机制保障。
10.1.3 并发操作可能产生的问题
这里以库存管理为例,说明对并发操作不加以限制,会产生数据不一致性问题,这种问题共有三类。
1. 丢失更新
假设某产品库存量为50,现在购入该产品100个,执行入库操作,库存量加100;用掉40个,执行出库操作,库存量减40。分别用T1和T2表示入库和出库操作任务。
例如,同时发生入库(T1)和出库(T2)操作,这就形成并发操作。T1读取库存后,T2也读取了同一个库存;T1修改库存,回写更新后的值;T2修改库存,也回写更新后的值。此时库存为T2回写的值,T1对库存的更新丢失。如表10.1所示T1和T2的并发操作执行顺序,发生了“丢失更新”错误。
表10.1 发生丢失更新的过程
顺序 | 任务 | 操作 | 库存量 |
1 | T1 | 读库存量 | 50 |
2 | T2 | 读库存量 | 50 |
3 | T1 | 库存量=50+100 | |
4 | T2 | 库存量=50-40 | |
5 | T1 | 写库存量 | 150 |
6 | T2 | 写库存量 | 10 |
2. 读“脏数据”
当T1和T2并发执行时,在T1对数据库更新的结果没有提交之前,T2使用了T1的结果,而在T2操作之后T1又回滚,这时引起的错误是T2读取了T1的“脏数据”。表10.2所示的执行过程就产生了这种错误。
表10.2 T2使用T1的“脏数据”的过程
顺序 | 任务 | 操作 | 库存量 |
1 | T1 | 读库存量 | 50 |
2 | T1 | 库存量=50+100 | |
3 | T1 | 写库存量 | 150 |
4 | T2 | 读库存量 | 150 |
5 | T2 | 库存量=150-40 | |
6 | T1 | ROLLBACK | 50 |
7 | T2 | 写库存量 | 110 |
3. 不可重复读
当T1读取数据A后,T2执行了对A的更新,当T1 再次读取数据A(希望与第一次是相同的值)时,得到的数据与前一次不同,这时引起的错误称为“不可重复读”。表10.3所示的并发操作执行过程,发生了“不可重复读”错误。
并发操作之所以产生错误,是因为任务执行期间相互干扰造成的。当将任务定义成事务,事务具有的特性(特别是隔离性)得以保证时,就会避免上述错误的发生。但是,如果只允许事务串行操作会降低系统的效率。所以,多数DBMS采用事务机制和封锁机制进行并发控制,既保证了数据的一致性,又保障了系统效率。
表10.3 T1对数据A“不可重复读”的过程
顺序 | 任务 | 操作 | 库存量A | 入库量B |
1 | T1 | 读A=50 | 50 | 100 |
2 | T1 | 读B=100 | ||
3 | T1 | 求和=50+100 | ||
4 | T2 | 读B=100 | 50 | |
5 | T2 | B←B×4 | ||
6 | T2 | 回写B=400 | 50 | 400 |
7 | T1 | 读A=50 | 50 | |
8 | T1 | 读B=400 | ||
9 | T1 | 和=450 (验算不对) |
分析以上三种错误的原因,不难看出,上述三个操作序列违背了事务的四个特性。在产生并发操作时如何确保事务的特性不被破坏,避免上述错误的发生?这就是并发控制要解决的问题。