JDBC隔离级别 |
数据库隔离级别 |
数据访问情况 |
TRANSACTION_READ_UNCOMMITTED(未提交的读)Uncommitted Read |
ur |
就是俗称“脏读”(dirty read),在没有提交数据时能够读到已经更新的数据 |
TRANSACTION_READ_COMMITTED (游标稳定性)Cursor Stability |
cs |
在一个事务中进行查询时,允许读取提交前的数据,数据提交后,当前查询就可 以读取到数据。update数据时候并不锁住表 |
TRANSACTION_REPEATABLE_READ (读稳定性)Read Stability |
rs |
在一个事务中进行查询时,不允许读取其他事务update的数据,允许读取 到其他事务提交的新增数据 |
TRANSACTION_SERIALIZABLE (可重复的读)Repeatable Read |
rr |
在一个事务中进行查询时,不允许任何对这个查询表的数据修改。 |
“可重复的读”隔离级别rr
当使用可重复的读隔离级别时,在单个事务执行期间锁定该事务引用的所有行。使用这种隔离级别时,同一事务多次发出的同一个 SELECT 语句将始终产生同一结果;丢失更新、脏读、不可重复的读、幻像都不会发生。
使用可重复的读隔离级别的事务可以多次检索同一行集,并可以对它们执行任意次操作,直到由提交或回滚操作终止事务;不允许其它事务执行插入、更新或删除操 作,因为这些操作会在隔离事务存在期间影响正在被使用的行集。为了确保在“可重复的读”隔离级别下运行的事务所访问的数据不会受其它事务的负面影响,所以 锁定了该隔离事务所引用的每个行 — 而不是仅锁定被实际检索和/或修改的那些行。因此,如果一个事务扫描了 1000 行但只检索 10 行,则所扫描的 1000 行(而不仅是被检索的 10 行)都会被锁定。
那么在现实环境中这个隔离级别是如何工作的呢?假定您拥有一家大型旅馆,并有一个网站,该网站按“先到先服务”的原则接受客户的房间预订。如果您的旅馆预 订应用程序是在“可重复的读”隔离级别下运行的,当客户检索某个日期段内的所有可用房间列表时,您将无法更改那些房间在指定日期范围内的费用,而其他客户 也将无法进行或取消将会更改该列表的预订,直到生成该列表的事务终止为止。(对于第一个客户的查询所指定范围之外的任何房间,您都可以更改房价,其他客户 也都可以进行或取消房间预订。)
“读稳定性”隔离级别rs
当使用读稳定性隔离级别时,在单个事务执行期间,会锁定该事务所检索的所有行。当使用这种隔离级别时,直到隔离事务终止之前,其它事务不能更改隔离事务读 取的所有行。此外,其它事务对其它行所作的更改,在提交之前对于运行在“读稳定性”隔离级别下的事务而言是不可见的。因此,当使用“读稳定性”隔离级别 时,在同一事务中多次发出 SELECT 语句可能会产生不同的结果。丢失更新、脏读和不可重复的读都不会发生;但是,有可能出现幻像。
使用“可重复的读”隔离级别时,隔离事务引用的每一行都被锁定;但是,在“读稳定性”隔离级别下,只锁定隔离事务实际检索和/或修改的行。因此,如果一个 事务扫描了 1000 行但只检索 10 行,则只有被检索到的 10 行(而不是所扫描的 1000 行)被锁定。
那么,这种隔离级别会如何改变旅馆预订应用程序的工作方式呢?现在,当一个客户检索某个日期段内的所有可用房间列表时,您可以更改旅馆中任何房间的房价, 而其他客户也可以取消在第一个客户的查询所指定的日期段内所保留房间的预订。因此,如果在终止提交查询的事务之前再次生成列表,则产生的新列表中有可能包 含新的房价或第一次产生列表时不可用的房间。
“游标稳定性”隔离级别cs
当使用游标稳定性隔离级别时,只要隔离事务所用的游标定位在某一行上,就会锁定该游标所引用的这一行。所获取的锁一直有效,直到游标重定位(通常通过调用 FETCH 语句)或隔离事务终止为止。因此,当使用这种隔离级别时,在同一事务中多次发出 SELECT 语句可能会产生不同的结果。丢失更新和脏读不会发生;但有可能出现不可重复的读和幻像。
当使用“游标稳定性”隔离级别的事务通过可更新游标从表中检索行时,在游标定位在该行上时,其它事务不能更新或删除该行。但是,如果被锁定的行本身不是用 索引访问的,那么其它事务可以将新的行添加到表,并对位于被锁定行前后的行进行更新和/或删除操作。此外,如果隔离事务修改了它检索到的任何行,那么在隔 离事务终止之前,即使在游标不再位于这个被修改的行,其它事务不能更新或删除该行。
其它事务在其它行上进行的更改,在提交之前对于使用“游标稳定性”隔离级别的事务是不可见的。缺省情况下,大多数事务都使用“游标稳定性”隔离级别。
这种隔离级别对旅馆预订应用程序有什么影响呢?现在,当一个客户检索某个日期段内的所有可用房间列表,然后查看关于所产生的列表上每个房间的信息时(每次 查看一个房间),您可以更改旅馆中任何房间的房价,而其他客户可以对任何日期段的任何房间进行或取消预订;唯一的例外是第一个客户当前正在查看的房间。当 第一个客户查看列表中另一个房间的信息时,对于这个新房间也是一样;您现在可以更改第一个客户刚才查看的房间的房价,其他客户也可以预订该房间,但不能对 第一个客户当前正在查看的房间进行这些操作。
“未提交的读”隔离级别ur
在使用未提交的读隔离级别的情况中,当单个事务检索行时,仅当另一个事务试图删除或更改被检索的行所在的表时,才会在单个事务期间锁定这些行。因为在使用 这种隔离级别时,行通常保持未锁定状态,所以丢失更新、脏读、不可重复的读和幻像都可能会发生。
在大多数情况下,其它事务对行所作的更改,在提交或回滚之前对于使用“未提交的读”隔离级别的事务是可见的。但是,此类事务不能看见或访问其它事务所创建 的表、视图或索引,直到那些事务被提交为止。类似地,如果其它事务删除了现有的表、视图或索引,使用“未提交的读”隔离级别的事务仅当进行删除操作的事务 终止时才能了解这一情况。这种行为有一个例外:当运行在“未提交的读”隔离级别下的事务使用可更新游标时,该事务的行为和在“游标稳定性”隔离级别下运行 一样,并应用“游标稳定性”隔离级别的约束。
“未提交的读”隔离级别通常用于那些访问只读表的事务和/或某些执行 SELECT 语句的事务,这些语句对其它事务的未提交数据没有负面效果。
那么这种隔离级别对旅馆预订应用程序有什么影响呢?现在,当一个客户检索某个日期段内的所有可用房间列表时,您可以更改旅馆中任何房间的房价,而其它客户 也可以对任何日期段内的任何房间进行或取消预订。此外,如果其它客户取消了预订,即使他们还没有终止其事务并将那些取消提交到数据库,所生成的列表就可以 包含这些取消预订的房间了。
2. 数据库之间的差异:
1).Oracle通过具有意向锁的多粒度封锁机制进行并发控制,保证数据的一致性。其DML锁 (数据锁)分为两个层次(粒度):即表级和行级。通常的DML操作在表级获得的只是意向锁(RS或RX),其真正的封锁粒度还是在行级;DB2也是通过具 有意向锁的多粒度封锁机制进行并发控制,保证数据的一致性。其DML锁(数据锁)分为两个层次(粒度):即表级和行级。通常的DML操作在表级获得的只是 意向锁(IS,SIX或IX),其真正的封锁粒度也是在行级;另外,在Oracle数据库中,单纯地读数据(SELECT)并不加锁,这些都提高了系统的 并发程度,Oracle强调的是能够"读"到数据,并且能够快速的进行数据读取。而DB2的锁强调的是"读一致性",进行读数据(SELECT)时会根据 不同的隔离级别(RR,RS,CS)而分别加 S,IS,IS锁,只有在使用UR隔离级别时才不加锁。从而保证不同应用程序和用户读取的数据是一致的。
2). 在支持高并发度的同时,DB2和Oracle对锁的操纵机制有所不同:Oracle利用意向锁及数据行上加锁标志位等设计技巧,减小了Oracle维护行 级锁的开销,使其在数据库并发控制方面有着一定的优势。而DB2中对每个锁会在锁的内存(locklist)中申请分配一定字节的内存空间,具体是X锁 64字节内存,S锁32字节内存(注:DB2 V8之前是X锁72字节内存而S锁36字节内存)。
3). Oracle数据库中不存在锁升级,而DB2数据库中当数据库表中行级锁的使用超过locklist*maxlocks会发生锁升级。
4). 在Oracle中当一个session对表进行insert,update,delete时候,另外一个session仍然可以从Orace回滚段或者还 原表空间中读取该表的前映象(before image); 而在DB2中当一个session对表进行insert,update,delete时候,另外一个session仍然在读取该表数据时候会处于lock wait状态,除非使用UR隔离级别可以读取第一个session的未提交的值;所以Oracle同一时刻不同的session有读不一致的现象,而 DB2在同一时刻所有的session都是"读一致"的。
5). db2缺省下是使用cs级别,oracle缺省是使用ur.