为了保证数据的一致性,每个用戸必须看到一致的数据集,它包含该用户的事务以及其他用户的事务所做的所有更改。在单用户的数据库中,达到数据的一致性是一件很容易的事情。但是,现实的数据库需要允许众多的用户同时操作,这就是所谓的数据并发性。事务中不恰当的交互可能会导致数据不一致。
事务并发性通过管理各种用户的并发事务,来实现不允许它们起冲突。如果你是数据库的唯一用户,则不需要操心事务的并发控制。但是,在大多数情况下,数据库允许成千上万的用户同时对相同的表执行选择、更新、插入和删除等事务。
并发控制的一种方案是在每个操作期间锁定整个表,因此,一个用户的事务不会影响另一个用户的事务。这样,每个用户的操作被隔离,从而牺牲数据的并发性。这表示对表的访问将极大地减少。Oracle确实使用锁定机制来保证数据的一致性,但为了保持最大的并发性,锁定采用的是最少限制的方式。毫无疑问,并发性提高了RDBMS的吞吐量,但也带来了特殊的问题,
并发性带来的问题
多用户对数据库的并发访问带来几个问题。并发处理中可能遇到的几个最重要的问题是脏读 (dirty read)、幻读(phantom read)、更新丢失(lost update)和不可重复读(nonrepeatable read)。
1.脏读问题(dirty read)
当B事务读取由A正在进行的事务更新但未永久提交给数据库的数据时,发生脏读。例如,假如事务A刚更新了某个列的值,而它又被事务B读取。如果事务A冋滚其更改,不管是故意的还是由于某种原因而中止,怎么办?结果是,已更新的列值也将被回滚。然而,事务B已经读取了该列的新值,但现在它是不正确的值了,因为事务A已经回滚。
提示 本节描述的问题可以通过施加一个简单的规则来避免,这就是:在一个事务提交或回滚之前,不要让其他事务读取其中间结果。这样,就保证了读的一致性。
2.幻读问题(phantom read)
假如你正从一个表读数据(使用SELECT语句)。过一段时间后,又重新执行一遍査询,与此同时,其他用户已经插入新数据到表中。因为你的第二次查询将遇到第-次读时未遇到的行,这就是所谓的"幻读",由此产生的问题称为幻读问题。幻读问题是由一个事务的两个数据库操作之间出现新数据而导致的。
3.更新丢失问题(lost update)
更新丢失问题是由某事务试图在数据被其他事务更新时读取它所导致的问题。假如事务A正在读一个表的数据,而此数据正被事务B更新,事务B成功完成并提交。如果事务A在事务B成功完成前已经读取数据,则它读取的可能是中间数据。由于两个用户更新了相同的行,并且第二次更新覆盖了第一次的更新,则第一次更新丢失,此时这种不正常的丢失更新便出现了。这是一个事务完成之前允许其他事务读和更新一个表所引起的问题。
4.不可重复读(模糊读)问题(nonrepeatable read)
当一个事务发现它以前读的数据己经被其他事务修改,不可重复读(或模糊读)问题就产生了。假如你在某个时间点访问一个表的数据,稍后又试图访问相同的数据,发现第二次读的数据与第一次的不同了。这种相同事务中不一致的数据导致不可重复读问题。
进度表和串行性
所有数据问题都是由并发访问所导致的,可以肯定地设想,隔离执行的一个事务完成时,总是使数据库处于一致状态。如果数据瘁允许并发访问,则需要考虑所有事务对数据库一致性的累积效果。
为此,数据库使用一个进度表,它是一个或多个事务的操作序列。如果所有事务串行地执行,即一个接一个地执行,此进度表也应该是串行的。如果数据库能够生成一个在效果上等价于一个串行进度表的进度表,即使它可能是从一组并发事务导出的,则也称此进度表为串行的进度表。串行的进度表由来自几个事务的一系列中间数据库操作组成,其最终输出是一个一致性的数据库。
可以想象,在实际中推导出一个进度表并不容易。但是,用户在使用事务时不必关心串行机制。Oracle数据库通过使用隔离级别和撤销数据的管理,会自动导出串行进度表。