• Sd


    SQL92事务的隔离级别

     

      SQL 标准用三个必须在并行的事务之间避免的现象定义了四个级别的事务隔离。 这些不希望发生的现象是: 

     
        脏读(dirty reads)一个事务读取了另一个未提交的并行事务写的数据。

     

        不可重复读(non-repeatable reads )一个事务重新读取前面读取过的数据,发现该数据已经被另一个已提交的事务修改过。

     

        幻读(phantom read )一个事务重新执行一个查询,返回一套符合查询条件的行,发现这些行因为其他最近提交的事务而发生了改变。

     

        这四种隔离级别和对应的行为在表Table 12-1中描述:

     

       SQL事务隔离级别

     

    隔离级别
    脏读 (Dirty Read)
    不可重复读 (NonRepeatable Read)
    幻读 (Phantom Read)
    读未提交(Read uncommitted)
    可能
    可能
    可能
    读已提交(Read committed)
    不可能
    可能
    可能
    可重复读(Repeatable read)
    不可能
    不可能
    可能
    可串行化(Serializable)
    不可能
    不可能
    不可能

     

     

     

        在 PostgreSQL 里,你可以请求四种可能的事务隔离级别中的任意一种。但是在内部,实际上只有两种独立的隔离级别,分别对应读已提交可串行化。如果你选择了读未提交的级别,实际上你用的是读已提交,在你选择可重复的读级别的时候,实际上你用的是可串行化,所以实际的隔离级别可能比你选择的更严格。这是 SQL 标准允许的:四种隔离级别只定义了哪种现象不能发生,但是没有定义那种现象一定发生。 PostgreSQL 只提供两种隔离级别的原因是,这是把标准的隔离级别与多版本并发控制架构映射相关的唯一的合理方法。可用的隔离级别的行为在下面小节里描述。

     

     

     

    1、读已提交隔离级别

     

     

     

        读已提交(Read Committed) 是 PostgreSQL 里的缺省隔离级别。当一个事务运行在这个隔离级别时,一个 SELECT 查询只能看到查询开始之前提交的数据而永远无法看到未提交的数据或者是在查询执行时其他并行的事务提交做的改变。(不过 SELECT 的确看得见同一次事务中前面更新的结果。即使它们还没提交也看得到) 实际上,一个 SELECT 查询看到一个在该查询开始运行的瞬间该数据库的一个快照。 请注意两个相邻的 SELECT 命令可能看到不同的数据,哪怕它们是在同一个事务里,因为其它事务会在第一个SELECT执行的时候提交。

     

     

     

        UPDATE、 DELETE或者 SELECT FOR UPDATE 在搜索目标行的时候的行为和SELECT 一样:它们只能找到在命令开始的时候已经提交的行。不过,这样的目标行在被找到的时候可能已经被其它并发的事务更新 (或者删除,或者标记为更新的)。在这种情况下,即将进行的更新将等待第一个更新事务提交或者回滚 (如果它还在处理)。 如果第一个更新回滚,那么它的作用将被忽略,而第二个更新者将继续更新最初发现的行。如果第一个更新者提交,那么如果第一个更新者删除了该行,则第二个更新者将忽略该行,否则它将试图在该行的已更新的版本上施加它的操作。系统将重新计算命令搜索条件(WHERE 子句),看看该行已更新的版本是否仍然符合搜索条件。如果是,则第二个更新继续其操作,从该行的已更新版本开始。

     

     

     

        因为上面的规则,正在更新的命令可能会看到不一致的快照 —— 它们可以看到影响它们试图更新的并发更新命令的效果,但是它们看不到那些命令对数据库里其它行的作用。这样的行为令读已提交模式不适合用于哪种涉及复杂搜索条件的命令。不过,它对于简单的情况而言是正确的。比如,假设我们用类似下面这样的命令更新银行余额:

     

     

     

        BEGIN;     UPDATE accounts SET balance = balance + 100.00 WHERE acctnum = 12345;     UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 7534;     COMMIT;

     

        如果两个并发事务试图修改帐号 12345 的余额,那我们很明显希望第二个事务是从帐户行的已经更新过的版本上进行更新。因为每个命令只是影响一个已经决定了的行,因此让它看到更新后的版本不会导致任何不一致的问题。

     

     

     

        因为在读已提交模式里,每个新的命令都是从一个新的快照开始的,而这个快照包含所有到该时刻为止已经提交的事务,因此同一个事务里的后面的命令将看到任何已提交的并发事务的效果。 这里要考虑的问题是我们在一个命令里是否看到数据库里绝对一致的视图。

     

     

     

        读已提交模式提供的部分事务隔离对于许多应用而言是足够的,并且这个模式速度快,使用简单。不过,对于做复杂查询和更新的应用,可能需要保证数据库有比读已提交模式提供的更加严格的一致性视图。

     

     

     

    2、可串行化隔离级别

     

        可串行化(Serializable) 级别提供最严格的事务隔离。这个级别模拟串行的事务执行,就好象事务将被一个接着一个那样串行的,而不是并行的执行。不过,使用这个级别的应用必须准备在串行化失败的时候重新发动事务。

     

     

     

        当一个事务处于可串行化级别,一个 SELECT 查询只能看到在事务开始之前提交的数据而永远看不到未提交的数据或事务执行中其他并行事务提交的修改。(不过,SELECT 的确看得到同一次事务中前面的更新的效果。即使事务还没有提交也一样) 这个行为和读已提交级别是不太一样,它的 SELECT 看到的是该事务开始时的快照,而不是该事务内部当前查询开始时的快照。这样,一个事务内部后面的 SELECT 命令总是看到同样的数据。

     

     

     

        UPDATE、DELETE和 SELECT FOR UPDATE 在搜索目标行上的行为和 SELECT 一样:它们将只寻找在事务开始的时候已经提交的目标行。但是,这样的目标行在被发现的时候可能已经被另外一个并发的事务更新了(或者是删除或者是标记为更新)。在这种情况下,可串行化的事务将等待第一个正在更新的事务提交或者回滚 (如果它仍然在处理中)。 如果第一个更新者回滚,那么它的影响将被忽略, 而这个可串行化的就可以继续更新它最初发现的行。但是如果第一个更新者提交了 (并且实际上更新或者删除了该行,而不只是为更新选中它) 那么可串行化事务将回滚,并返回下面信息:

     

        ERROR:  Can't serialize access due to concurrent update

     

        因为一个可串行化的事务在可串行化事务开始之后不能更改被其他事务更改过的行。

     

     

     

        当应用收到这样的错误信息时,它应该退出当前的事务然后从头开始重新进行整个事务。第二次运行时,该事务看到的前一次提交的修改是该数据库初始的样子中的一部分, 所以把新版本的行作为新事务更新的起点不会有逻辑冲突。

     

     

     

        请注意只有更新事务才需要重试,只读事务从来没有串行化冲突

     

     

     

        可串行化事务级别提供了严格的保证:每个事务都看到一个完全一致的数据库的视图。不过,如果并行更新令数据库不能维持串行执行的样子,那么应用必须准备重试事务。因为重做复杂的事务的开销可能是非常可观的,所以我们只建议在更新命令中包含足够复杂的逻辑,在读已提交级别中可能导致错误的结果的情况下才使用。最常见的是,可串行化模式只是在这样的情况下是必要的:一个事务连续做若干个命令, 而这几个命令必须看到数据库完全一样的视图。

     

     

     

    3、可串行化隔离与真正的可串行化之比较

     

        执行的“可串行化”的直观含义(以及数学定义)是两个成功提交的并发事务将显得好像严格地串行执行一样,一个跟着一个 —— 尽管我们可能无法预期哪个首先执行。我们必须明白,禁止那些在 Table 12-1 里面列出的行为并不能保证真正的可串行化。并且,实际上 PostgreSQL 的可串行化模式并不保证在这种含义下的可串行化。举例来说,假设一个表 mytab,最初包含

     

     

     

    class | value -------+-------      1 |    10      1 |    20      2 |   100      2 |   200

     

     

     

        假设可串行化事务 A 计算: SELECT SUM(value) FROM mytab WHERE class = 1;  然后把结果(30)作为 value 到表中,class = 2。 同时,一个并发的可串行化的事务 B 进行下面计算: SELECT SUM(value) FROM mytab WHERE class = 2;  并且获取结果 300,然后它插入一行新行,class = 1

     

     

     

        然后两个事务都提交。所有列出的禁止行为都不会发生,但是我们拿到的结果是不可能在任何一种串行执行下看到的。如果 A 在 B 之前执行,B 应该计算出总和 330,而不是 300,如果是另外一种顺序,那么 A 计算出的总和也会不同。

     

     

     

        为了保证真正数学上的可串行化,一个数据库系统必须强制谓词锁定, 这就意味着一个事务不能插入或者更改这样的数据行:这个数据行的数据匹配另外一个并发事务的 WHERE 条件。 比如,一旦事务 A 执行了查询 SELECT ... WHERE class = 1,那么一个谓词锁定系统将禁止事务 B 插入任何 class 为 1 的新行,直到 A 提交。 实际上,一个谓词锁定系统避免了幻读,方法是约束写入的东西,而 MVCC 避免幻读的方法是约束它读取的东西。这样的锁系统实现起来非常复杂,并且执行起来代价高昂,因为每个会话都必须要知道每个并发事务的每个查询的执行细节。并且这样大量的开销在大部分情况下都是浪费掉的,因为在实际情况下大部分应用都不做会导致问题的这种事情。(当然,上面的例子是静心设计的,不能代表真实的软件。) 因此,PostgreSQL 并未实现谓词锁定,而就我们所知,没有其它的生产中的 DBMS 实现了这个。

     

     

     

        在那些非串行化执行真的可能有危险的场合,可以通过使用明确的锁定来避免问题的发生

     

     

    Oracle事务的隔离级别

     

     

    数据库的锁(一般定义)

      

      

      

     

      锁的2种最基本、最简单的类型:排他锁(eXclusive lock,即X锁)、共享锁(Share lock,即S锁)。 不同级别的锁定协议及其作用:

     

    申请的锁

    及其作用

    锁定协议

    修改时申请X锁

    读取时申请S锁

    作用

    操作

    结束

    释放

    事务

    结束

    释放

    操作

    结束

    释放

    事务

    结束

    释放

    丢失

    修改

    脏读

    重复读

    一级锁定协议

     

       

       

    二级锁定协议

     

     

     

    三级锁定协议

     

     

     

      锁定对象的大小被称为锁定的粒度(granularity)。 如果在一个数据库管理系统中,同时支持多种锁定粒度供事务选择,这种锁定方法就被称为多粒度锁定(multiple granularity locking)。 多粒度锁定协议是指,允许对多粒度树中的节点单独地加锁,另外,对一个节点加锁还意味着对这个节点的各级子节点也加同样的锁。因此,可以用两种方法对多粒度树中的节点加锁:显式锁定、隐式锁定。显式锁定是在事务中明确指定要加在节点上的锁;隐式锁定是由于在其上级节点中加显式锁时而使该节点获得的锁。

      具有意向锁的多粒度锁定方法能提高系统的并发度,减少加锁和解锁的开销。 意向锁的含义是,如果对一个节点加某种意向锁,则表示对它的所有下级节点加这种锁的意向;如果对一个节点加某种锁,则必须先对该节点的各级上级节点加这种意向锁。 有如下几种意向锁。 一、IS锁(Intended Share lock,意向共享锁) 二、IX锁(Intended eXclusive lock,意向排他锁) 三、SIX锁(Share Intended eXclusive lock,共享意向排他锁) 如果对一个节点加SIX锁,则表示对它加S锁,然后再加IX锁,即SIX=S+IX。例如,如果事务T对表A加SIX锁,则表示事务T要读取整个表(S锁的作用),同时还会更新某些记录(IX锁的作用)。 包括意向锁的各种锁之间的相容规则:(NL表示没有锁定)

     

        T保持的锁 Ti想获取的锁 NL  IS 

    IX 

    SIX 
     IS  可以  可以  可以  可以 可以   不可以
     IX  可以  可以  可以  不可以  不可以  不可以
     S  可以  可以  不可以  可以  不可以  不可以
     SIX  可以  可以  不可以  不可以  不可以  不可以
     X  可以  不可以  不可以  不可以  不可以  不可以

     

      死锁是一种比较严重的、特殊的锁争用类型。在这种锁争用中,两个或两个以上的用户正在等待对方锁定的资源。因此,如果不进行某种干预,任意一个事务都无法完成。 诊断死锁方法有: *超时法。如果一个事务的等待时间超过了规定的时限,就认为发生了死锁。 *等待图法。这是用离散数学的图论来诊断死锁的方法。事务的等待图是一个有向图G=(T,U)。T为正在运行的各个事务的节点的集合,U为有向边。如果T1 事务等待T2事务,则在T1、T2节点之间就有一条从T1指向T2的有向边。DBMS的并发控制子系统周期性地(如每隔1分钟)检测事务等待图。如果发现图中存在回路,则表示系统中出现了死锁。

     

     

    Oracle的锁

     

     

    在数据库中有两种基本的锁类型:排它锁(Exclusive Locks,即X锁)和共享锁(Share Locks,即S锁)。当数据对象被加上排它锁时,其他的事务不能对它读取和修改;加了共享锁的数据对象可以被其他事务读取,但不能修改。

     

    根据保护对象的不同,Oracle数据库锁可以分为以下几大类:

     

    (1) DML lock(data locks,数据锁):用于保护数据的完整性;

     

    (2) DDL lock(dictionary locks,字典锁):用于保护数据库对象的结构(例如表、视图、索引的结构定义);

     

    (3) Internal locks 和latches(内部锁与闩):保护内部数据库结构;

     

    (4) Distributed locks(分布式锁):用于OPS(并行服务器)中;

     

    (5) PCM locks(并行高速缓存管理锁):用于OPS(并行服务器)中。

     

    在Oracle中最主要的锁是DML(也可称为data locks,数据锁)锁。DML锁的目的在于保证并发情况下的数据完整性。在Oracle数据库中,DML锁主要包括TM锁和TX锁,其中TM锁称为表级锁,TX锁称为事务锁或行级锁。

     

    意向锁的含义是如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁;对任一结点加锁时,必须先对它的上层结点加意向锁。如:对表中的任一行加锁时,必须先对它所在的表加意向锁,然后再对该行加锁。这样一来,事务对表加锁时,就不再需要检查表中每行记录的锁标志位了,系统效率得以大大提高。

     

    TM锁(表级锁)类型共有5种,分别称为共享锁(S锁)、排它锁(X锁)、行级共享锁(RS锁)、行级排它锁(RX锁)、共享行级排它锁(SRX锁)

     

    当Oracle执行DML语句时,系统自动在所要操作的表上申请TM类型的锁。当TM锁获得后,系统再自动申请TX类型的锁,并将实际锁定的数据行的锁标志位进行置位。这样在事务加锁前检查TX锁相容性时就不用再逐行检查锁标志,而只需检查TM锁模式的相容性即可,大大提高了系统的效率。TM锁包括了SS、SX、S、X等多种模式,在数据库中用0-6来表示。不同的SQL操作产生不同类型的TM锁。如表1所示。

     

    表1 Oracle的TM锁类型

    锁模式

    锁描述

    解释

    SQL操作

    0

    none

    1

    NULL

    Select

    2

    SS(Row-S)

    行级共享锁,其他对象只能查询这些数据行

    Select for update、Lock for update、Lock row share

    3

    SX(Row-X)

    行级排它锁,在提交前不允许做DML操作

    Insert、Update、Delete、Lock row share

    4

    S(Share)

    共享锁

    Create index、Lock share

    5

    SSX(S/Row-X)

    共享行级排它锁

    Lock share row exclusive

    6

    X(Exclusive)

    排它锁

    Alter table、Drop able、Drop index、Truncate table 、Lock exclusive

     

    1. 共享锁(Share Table Lock,S):

     

    加锁语法:Lock Table TableName In Share Mode;

     

    允许的操作:一个共享锁由一个事务控制,仅允许其它事务查询被锁定的表。一个有效的共享锁明确地用Select … For update形式锁定行,或执行Lock Table TableName In Share Mode语法锁定整个表,不允许被其它事务更新。

     

    禁止的操作:一个共享锁由一个事务来控制,防止其它事务更新该表或执行下面的语句:

     

    LOCK TABLE TableName IN SHARE ROW EXCLUSIVE MODE;

     

    LOCK TABLE TableName IN ROW EXCLUSIVE MODE;

     

    2. 排它锁(Exclusive Table Lock,X):

     

    排它锁是在锁机制中限制最多的一种锁类型,允许加排它锁的事务独自控制对表的写权限。

     

    加锁语法:Lock Table TableName In Exclusive Mode;

     

    允许的操作:在一个表中只能有一个事务对该表实行排它锁,排它锁仅允许其它的事务查询该表。

     

    禁止的操作:拥有排外锁的事务禁止其它事务执行其它任何DML类型的语句或在该表上加任何其它类型的锁。

     

    定义排它锁的语法:

     

    LOCK TABLE TableName IN EXCLUSIVE MODE;

     

    3. 行级锁(Row Share Table Lock,RS):

     

    一个行级锁(有时称为Subshare Table Lock,简称SS,子共享锁)需要该事务在被锁定行的表上用update的形式加锁。当有下面语句被执行的时候行级锁自动加在操作的表上。

     

    SELECT . . . FROM TableName. . . FOR UPDATE OF . . . ;

     

    LOCK TABLE TableName IN ROW SHARE MODE;

     

    行级锁(Row Share Table Lock)在锁类型中是限制最少的,也是在表的并发程度中使用程度最高的。

     

    允许的操作:行级共享锁由一个事务控制,允许其它事务查询、插入、更新、删除或同时在同一张表上锁定行。因此其它事务可以同时在同一张表上得到行级锁、共享行级排它锁、行级排它锁、排它锁。

     

    禁止的操作:拥有行级锁的事务不允许其它事务执行排它锁,即:

     

    Lock Table TableName In Exclusive Mode;

     

    4. 行级排它锁(Row Exclusive Table Lock,RX):

     

    行级排它锁(亦称为Subexclusive Table Lock,简称SX,子排它锁)通常需要事务拥有的锁在表上被更新一行或多行。当有下面语句被执行的时候行级排它锁被加在操作的表上。

     

    INSERT INTO TableName. . . ;

     

    UPDATE TableName. . . ;

     

    DELETE FROM TableName. . . ;

     

    LOCK TABLE TableName IN ROW EXCLUSIVE MODE;

     

    行级排它锁比行级锁稍微多一些限制。

     

    允许的操作:行级排它锁由一个事务拥有允许其它事务执行查询、修改、插入、删除或同时在同一张表上锁定行。执有行级排它锁的事务允许其它事务在同一张表上同时得到共享锁和行级排它锁。

     

    禁止的操作:行级排它锁由一个事务拥有防止其它事务手动锁定表来排除其它事务的读写权。因此,其它事务不允许在同一张表上使用以下的语句来执行锁事务。

     

    LOCK TABLE table IN SHARE MODE;

     

    LOCK TABLE table IN SHARE EXCLUSIVE MODE;

     

    LOCK TABLE table IN EXCLUSIVE MODE

     

    5. 共享行级排它锁(Share Row Exclusive Table Lock,SRX):

     

    共享行级排它锁有时也称共享子排它锁(Share Subexclusive Table Lock,SSX),它比共享锁有更多限制。定义共享行级排它锁的语法为:

     

    Lock Table TableName In Share Row Exclusive Mode;

     

    允许的操作:仅允许一个事务在某一时刻得到行级排它锁。拥有行级排它锁事务允许其它事务在被锁定的表上执行查询或使用Select … From TableName For update…来准确在锁定行而不能更新行。

     

    禁止的操作:拥有行级排它锁的事务不允许其它事务有除共享锁外的其它形式的锁加在同一张表上或更新该表。即下面的语句是不被允许的:

     

    LOCK TABLE TableName IN SHARE MODE;

     

    LOCK TABLE TableName IN SHARE ROW EXCLUSIVE MODE;

     

    LOCK TABLE TableName IN ROW EXCLUSIVE MODE;

     

    LOCK TABLE TableName IN EXCLUSIVE MODE;

     

    当Oracle数据库发生TX锁等待时,如果不及时处理常常会引起Oracle数据库挂起,或导致死锁的发生,产生ORA-60的错误。

     

    TX锁等待的分析

     

    Oracle数据库中一般使用行级锁。

     

    当Oracle检测到死锁产生时,中断并回滚死锁相关语句的执行,报ORA-00060的错误并记录在数据库的日志文件alertSID.log中。同时在user_dump_dest下产生了一个跟踪文件,详细描述死锁的相关信息。

     

    在日常工作中,如果发现在日志文件中记录了ora-00060的错误信息,则表明产生了死锁。这时需要找到对应的跟踪文件,根据跟踪文件的信息定位产生的原因。

     

    表2 数据字典视图说明

    视图名

    描述

    主要字段说明

    v$session

    查询会话的信息和锁的信息。

    sid,serial#:表示会话信息。

    program:表示会话的应用程序信息。

    row_wait_obj#:表示等待的对象,和dba_objects中的object_id相对应。

    v$session_wait

    查询等待的会话信息。

    sid:表示持有锁的会话信息。

    Seconds_in_wait:表示等待持续的时间信息

    Event:表示会话等待的事件。

    v$lock

    列出系统中的所有的锁。

    Sid:表示持有锁的会话信息。

    Type:表示锁的类型。值包括TM和TX等。

    ID1:表示锁的对象标识。

    lmode,request:表示会话等待的锁模式的信

    息。用数字0-6表示,和表1相对应。

    dba_locks

    对v$lock的格式化视图。

    Session_id:和v$lock中的Sid对应。

    Lock_type:和v$lock中的type对应。

    Lock_ID1: 和v$lock中的ID1对应。

    Mode_held,mode_requested:和v$lock中

    的lmode,request相对应。

    v$locked_object

    只包含DML的锁信息,包括回滚段和会话信息。

    Xidusn,xidslot,xidsqn:表示回滚段信息。和

    v$transaction相关联。

    Object_id:表示被锁对象标识。

    Session_id:表示持有锁的会话信息。

    Locked_mode:表示会话等待的锁模式的信

    息,和v$lock中的lmode一致。

     

    解锁及Kill Session:

     

    使用下面的语法查出锁并杀掉Session。

     

    SELECT A.SID,A.SERIAL#,A.USERNAME,B.TYPE FROM V$SESSION A,V$LOCK B WHERE A.SID=B.SID;

     

    ALTER SYSTEM KILL SESSION 'SID,SERIAL#';

     

     

    Oracle的并发控制

     

    Spring事务的传播性

       

        ********************sample***********************
    ServiceA {
           
         /**
          * 事务属性配置为 PROPAGATION_REQUIRED
          */

         void methodA() {
             ServiceB.methodB();
         }
      
    }
      
    ServiceB {
           
         /**
          * 事务属性配置为 PROPAGATION_REQUIRED
          */

         void methodB() {
         }
           
    }
    *************************************************
    1: PROPAGATION_REQUIRED
    加入当前正要执行的事务不在另外一个事务里,那么就起一个新的事务
    比如说,ServiceB.methodB的事务级别定义为PROPAGATION_REQUIRED, 那么由于执行ServiceA.methodA的时候,
    ServiceA.methodA已经起了事务,这时调用ServiceB.methodB,ServiceB.methodB看到自己已经运行在ServiceA.methodA
    的事务内部,就不再起新的事务。而假如ServiceA.methodA运行的时候发现自己没有在事务中,他就会为自己分配一个事务。
    这样,在ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都会被回滚。即使ServiceB.methodB的事务已经被
    提交,但是ServiceA.methodA在接下来fail要回滚,ServiceB.methodB也要回滚

    2: PROPAGATION_SUPPORTS
    如果当前在事务中,即以事务的形式运行,如果当前不再一个事务中,那么就以非事务的形式运行


    3: PROPAGATION_MANDATORY
    必须在一个事务中运行。也就是说,他只能被一个父事务调用。否则,他就要抛出异常

    4: PROPAGATION_REQUIRES_NEW
    这个就比较绕口了。 比如我们设计ServiceA.methodA的事务级别为PROPAGATION_REQUIRED,ServiceB.methodB的事务级别为PROPAGATION_REQUIRES_NEW,
    那么当执行到ServiceB.methodB的时候,ServiceA.methodA所在的事务就会挂起,ServiceB.methodB会起一个新的事务,等待ServiceB.methodB的事务完成以后,
    他才继续执行。他与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为ServiceB.methodB是新起一个事务,那么就是存在
    两个不同的事务。如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。如果ServiceB.methodB失败回滚,
    如果他抛出的异常被ServiceA.methodA捕获,ServiceA.methodA事务仍然可能提交。

    5: PROPAGATION_NOT_SUPPORTED
    当前不支持事务。比如ServiceA.methodA的事务级别是PROPAGATION_REQUIRED ,而ServiceB.methodB的事务级别是PROPAGATION_NOT_SUPPORTED ,
    那么当执行到ServiceB.methodB时,ServiceA.methodA的事务挂起,而他以非事务的状态运行完,再继续ServiceA.methodA的事务。

    6: PROPAGATION_NEVER
    不能在事务中运行。假设ServiceA.methodA的事务级别是PROPAGATION_REQUIRED, 而ServiceB.methodB的事务级别是PROPAGATION_NEVER ,
    那么ServiceB.methodB就要抛出异常了。

    7: PROPAGATION_NESTED
    理解Nested的关键是savepoint。他与PROPAGATION_REQUIRES_NEW的区别是,PROPAGATION_REQUIRES_NEW另起一个事务,将会与他的父事务相互独立,
    而Nested的事务和他的父事务是相依的,他的提交是要等和他的父事务一块提交的。也就是说,如果父事务最后回滚,他也要回滚的。
    而Nested事务的好处是他有一个savepoint。
    *****************************************
    ServiceA {

    /**
    * 事务属性配置为 PROPAGATION_REQUIRED
    */

    void methodA() {
    try {
    //savepoint

    ServiceB.methodB(); //PROPAGATION_NESTED 级别

    } catch (SomeException) {
    // 执行其他业务, 如 ServiceC.methodC();

    }
    }

    }
    ********************************************
    也就是说ServiceB.methodB失败回滚,那么ServiceA.methodA也会回滚到savepoint点上,ServiceA.methodA可以选择另外一个分支,比如
    ServiceC.methodC,继续执行,来尝试完成自己的事务。
    但是这个事务并没有在EJB标准中定义。

     

    J2EE的事务控制策略概述

      http://www.cnblogs.com/heartstage/p/3418667.html

     

    Hibernate的事务控制

      

      

     

      http://ch-space.iteye.com/blog/380419

      http://tech.sina.com.cn/s/2005-08-19/1153698440.shtml

      

      http://bbs.csdn.net/topics/380260812

      http://blog.163.com/zhoutianwen_999/blog/static/96040562200801921247753/

      http://www.iteye.com/topic/177988

      

      

     

    Oracle中的事务和SQLServer中的事务的差异

    在SQL92标准中,事务隔离级别分为四种,分别为:Read Uncommitted、Read Committed、Read Repeatable、Serializable,其中Read Uncommitted与Read Committed为语句级别的,而Read Repeatable与Serializable是针对事务级别的。

      在Oracle和SQL Server中设置事务隔离级别的语句是相同的,都使用SQL92标准语法,即:

      Set Transaction Isolation Level Read Committed

      上面示例中的Read Committed可以被替换为其他三种隔离级别中的任意一种。

      1.SQL Server中的隔离级别及实现机制

      在SQL Server中提供了所有这四种隔离级别。

      下面我们讨论在SQL Server中,这几种隔离级别的含义及其实现方式。

      Read Uncommitted:一个会话可以读取其他事务未提交的更新结果,如果这个事务最后以回滚结束,这时的读取结果就可能是错误的,所以多数的数据库应用都不会使用这种隔离级别。

      Read Committed:这是SQL Server的缺省隔离级别,设置为这种隔离级别的事务只能读取其他事务已经提交的更新结果,否则,发生等待,但是其他会话可以修改这个事务中被读取的记 录,而不必等待事务结束,显然,在这种隔离级别下,一个事务中的两个相同的读取操作,其结果可能不同。

      Read Repeatable:在一个事务中,如果在两次相同条件的读取操作之间没有添加记录的操作,也没有其他更新操作导致在这个查询条件下记录数增多,则两次 读取结果相同。换句话说,就是在一个事务中第一次读取的记录保证不会在这个事务期间发生改变。SQL Server是通过在整个事务期间给读取的记录加锁实现这种隔离级别的,这样,在这个事务结束前,其他会话不能修改事务中读取的记录,而只能等待事务结 束,但是SQL Server不会阻碍其他会话向表中添加记录,也不阻碍其他会话修改其他记录。

      Serializable:在一个事务中,读取操作的结果是在这个事务开始之前其他事务就已经提交的记录,SQL Server通过在整个事务期间给表加锁实现这种隔离级别。在这种隔离级别下,对这个表的所有DML操作都是不允许的,即要等待事务结束,这样就保证了在 一个事务中的两次读取操作的结果肯定是相同的。

      2.Oracle中的隔离级别及实现机制

      在Oracle中,没有Read Uncommitted及Repeatable Read隔离级别,这样在Oracle中不允许一个会话读取其他事务未提交的数据修改结果,从而避免了由于事务回滚发生的读取错误。Oracle中的 Read Committed和Serializable级别,其含义与SQL Server类似,但是实现方式却大不一样。

      在Oracle中,存在所谓的回滚段(Oracle9i之前版本)或撤销段(Oracle9i版本),Oracle在修改数据记录时,会把这些 记录被修改之前的结果存入回滚段或撤销段中,就是因为这种机制,Oracle对于事务隔离级别的实现与SQL Server截然不同。在Oracle中,读取操作不会阻碍更新操作,更新操作也不会阻碍读取操作,这样在Oracle中的各种隔离级别下,读取操作都不 会等待更新事务结束,更新操作也不会因为另一个事务中的读取操作而发生等待,这也是Oracle事务处理的一个优势所在。

      Oracle缺省的设置是Read Committed隔离级别(也称为语句级别的隔离),在这种隔离级别下,如果一个事务正在对某个表进行DML操作,而这时另外一个会话对这个表的记录进 行读取操作,则Oracle会去读取回滚段或撤销段中存放的更新之前的记录,而不会象SQL Server一样等待更新事务的结束。

      在Serializable隔离级别(也称为事务级别的隔离),事务中的读取操作只能读取这个事务开始之前已经提交的数据结果。如果在读取时, 其他事务正在对记录进行修改,则Oracle就会在回滚段或撤销段中去寻找对应的原来未经更改的记录(而且是在读取操作所在的事务开始之前存放于回滚段或 撤销段的记录),这时读取操作也不会因为相应记录被更新而等待。

  • 相关阅读:
    新项目调试思路
    cmstop核心
    jquery获取li中的各项属性值attr
    mysql表设计
    SQLServer系统表使用简介(sysobjects、syscolumns、syscomments等)转载
    死锁查询和处理
    this 关键字的用法
    C# 线程
    C# WCF的通信模式
    C# WCF之用接口创建服务契约、部署及客户端连接
  • 原文地址:https://www.cnblogs.com/heartstage/p/3423481.html
Copyright © 2020-2023  润新知