详细说明:数据库
当多个用户访问同一数据库时会发生的现象介绍以下:并发
在单用户环境中,每一个事务都是顺序执行的,而不会遇到与其余事务的冲突。可是,在多用户环境下,多个事务能够(并且经常)同时执行。所以每一个事务都有可能与其余正在运行的事务发生冲突。有可能与其余事务发生冲突的事务称为交错的 或并行的 事务,而相互隔离的事务称为串行化 事务,这意味着同时运行它们的结果与一个接一个连续地运行它们的结果没有区别。在多用户环境下,在使用并行事务时,会发生四种现象:性能
丢失更新:这种状况发生在两个事务读取并尝试更新同一数据时,其中一个更新会丢失。例如:事务 1 和事务 2 读取同一行数据,并都根据所读取的数据计算出该行的新值。若是事务 1 用它的新值更新该行之后,事务 2 又更新了同一行,则事务 1 所执行的更新操做就丢失了。因为设计 DB2 的方法,DB2 不容许发生此类现象。 spa
脏读:当事务读取还没有提交的数据时,就会发生这种状况。例如:事务 1 更改了一行数据,而事务 2 在事务 1 提交更改以前读取了已更改的行。若是事务 1 回滚该更改,则事务 2 就会读取被认为是未曾存在的数据。 设计
不可重复的读:当一个事务两次读取同一行数据,但每次得到不一样的数据值时,就会发生这种状况。例如:事务 1 读取了一行数据,而事务 2 在更改或删除该行后提交了更改。当事务 1 尝试再次读取该行时,它会检索到不一样的数据值(若是该行已经被更新的话),或发现该行不复存在了(若是该行被删除的话)。 对象
幻像:当最初没有看到某个与搜索条件匹配的数据行,而在稍后的读操做中又看到该行时,就会发生这种状况。例如:事务 1 读取知足某个搜索条件的一组数据行,而事务 2 插入了与事务 1 的搜索条件匹配的新行。若是事务 1 再次执行产生原先行集的查询,就会检索到不一样的行集。 索引
维护数据库的一致性和数据完整性,同时又容许多个应用程序同时访问同一数据,这样的特性称为并发性。 DB2 数据库用来尝试强制实施并发性的方法之一是经过使用隔离级别——经过‘事务、隔离级别、锁’机制,它决定在第一个事务访问数据时,如何对其余事务锁定或隔离该事务所使用的数据。 DB2 使用下列隔离级别来强制实施并发性:进程
可重复的读(Repeatable Read) 事务
读稳定性(Read Stability) 资源
游标稳定性(Cursor Stability)
未提交的读(Uncommitted Read)
可重复的读隔离级别能够防止全部现象,可是会大大下降并发性的程度(能够同时访问同一资源的事务数量)。未提交的读隔离级别提供了最大的并发性,可是后三种现象均可能出现。
DB2 UDB 支持如下隔离级别:
可重复读(Repeatable read,RR);
读稳定性(Read stability,RS);
游标稳定性(Cursor stability,CS);
未提交读(Uncommitted read,UR)。
下面分别讲述:
可重复读(Repeatable read,RR) 确保 工做单元(UOW)期间的任何表行读操做直到 UOW 完成,不会被其余应用程序进程更改。相似地,由另外一个应用程序进程更改的任何行直到由该应用程序进程提交,不会被读取。运行在 RR 级别的应用程序进程是彻底与并发应用程序进程的效果相隔离的。RR 隔离级别一般会直接对表加 S 锁,因此对并发的影响最大,但有一种状况例外:若是 WHERE 条件字段上建有主键或者 UNIQUE INDEX,而且经过主键或者 UNIQUE INDEX 进行查询,那么数据库将只对表加 IS 锁,结果行加 S 锁——在锁列表足够用,没有发生锁升级的状况下才成立,也就是说,这个时候 RR 级别 =RS 级别,这时不容许其余事务对这些行进行更新或者删除,由于对行的更新或者删除会对相应的行加 X 锁,这和行 S 锁相排斥;其余状况下,会直接对表加 S 锁,这时将不容许其余事务对任何行进行更新或者删除。
读稳定性(Read stability,RS)相似于 RR 。可是,运行在 RS 级别的应用程序进程不是彻底与并发应用程序进程的效果相隔离的。若是这样的应用程序进程不止一次发出一样的查询,它就会看到更改了的数据或者由其余应用程序进程添加的新的“幻影(phantom)”行。RS 隔离级别会对表加 IS 锁,结果行加 NS 锁,这时不容许其余事务对这些行进行更新(UPDATE/DELETE),可是容许插入任何行,由于对这些行的更新会对相应的行加 X 锁,这和行 NS 锁相排斥——上述说法基于锁列表足够用,没有发生锁升级的状况下才成立。
游标稳定性(Cursor stability,CS)也确保由另外一个应用程序进程更改的任何行直到被那个应用程序进程提交,不会被读取。 CS 隔离级别只确保每一个可更新游标的当前行不被其余应用程序进程更改;在 UOW 期间读过的行能够被其余应用程序进程更改。针对可滚动更新游标,在提交以前,会对全部结果行一直加 U 锁,不管游标滚动到什么地方; CS 隔离级别针对不可更新游标会对表加 IS 锁,若是未在 WHERE 条件字段上建立索引,查询首先会查找锁列表,检查锁列表中是否存在与 IS 锁相排斥的锁,若是存在的话,那么将等待全部持有排斥锁的事务提交,查询才能执行下去;若是 WHERE 条件字段建立了索引,而且使用了索引,那么查询将经过索引获得结果行,而后检查锁列表中是否存在与结果行相排斥的锁,若是存在的话,那么将等待全部持有排斥锁的事务提交,查询才能执行下去 .
未提交读(Uncommitted read,UR)对于某些操做,容许在 UOW 期间读过的任何行能够被其余应用程序进程更改,并容许读任何被另外一个应用程序进程更改过的行,即便该更改尚未提交。对于其余操做,UR 相似于 CS 。综上所述,离级别对并发性具备最显著的影响,不一样隔离级别得到的资源的锁定范围也不一样,若是全部事务都能作到不过度贪婪的占有锁资源——锁的范围大、占用时间长,那么事务之间发生锁冲突的可能性将大大下降,事务的并发性也将会很好。那么如何选择正确的隔离级别呢?
使用的隔离级别不只影响数据库对并发性的支持如何,并且影响并发应用程序的性能。一般,使用的隔离级别越严格,并发性就越小,某些应用程序的性能可能会越低,由于它们要等待资源上的锁被释放。那么,如何决定要使用哪一种隔离级别呢?最好的方法是肯定哪些现象是不可接受的,而后选择可以防止这些现象发生的隔离级别:
若是正在执行大型查询,并且不但愿并发事务所作的修改致使查询的屡次运行返回不一样的结果,则使用可重复的读隔离级别。
若是但愿在应用程序之间得到必定的并发性,还但愿限定的行在事务执行期间保持稳定,则使用读稳定性隔离级别。
若是但愿得到最大的并发性,同时不但愿查询看到未提交的数据,则使用游标稳定性隔离级别。
若是正在只读的表 / 视图 / 数据库上执行查询,或者并不介意查询是否返回未提交的数据,则使用未提交的读隔离级别。 对于统计类报表,不须要获得十分精确的数据,那么最好使用 UR 隔离级别,既能够节省昂贵的锁列表资源,也不会由于锁冲突影响其余事务的执行,同时也不会受到其余事务的影响,顺利的获得统计结果。未提交的读隔离级别一般用于那些访问只读表和视图的事务,以及某些执行 SELECT 语句的事务(只要其余事务的未提交数据对这些语句没有负面效果)。 顾名思义,其余事务对行所作的更改在已经提交以前对于使用未提交的读隔离级别的事务是可见的。可是,此类事务不能看见或访问其余事务所建立的表、视图或索引,直到那些事务被提交为止。相似地,若是其余事务删除了现有的表、视图或索引,那么仅当进行删除操做的事务终止时,使用未提交的读隔离级别的事务才能知道这些对象再也不存在了。(必定要注意一点:当运行在未提交的读隔离级别下的事务使用可更新游标时,该事务的行为和在游标稳定性隔离级别下运行同样,并应用游标稳定性隔离级别的约束。)