<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-204  評論-149  文章-0  trackbacks-0
    http://www.javaeye.com/topic/78674
    回帖中也有些需要注意的地方。。可以仔細看看

    先了解一下數據庫并發操作帶來的數據不一致性包括三類:丟失修改,不可重復讀(第二個事務修改,或插入,或刪除,應該說幻讀是指插入或刪除的情況),臟讀。
     

    T1

    T2

    T1

    T2

    T1

    T2

    A=16

    ①讀A=50

    讀B=150

    求和150

    ①讀C=100

    CC*2

    寫回C

    A=16

    B=100

    B=B*2

    寫回B=200

    C=200

    A=A-1

    寫回A=15

    ③讀A=50

    B200

    求和250

    ROLLBACk

    C恢復到100

    A=A-1

    寫回A=15

    丟失修改

    不可重復讀

    臟讀



    一般數據庫原理的書中通過“鎖”來解決這種并發操作帶來的問題

    基本的鎖類型有兩種:排它鎖Exclusive Locks簡稱X鎖和共享鎖Share Locks,簡稱S鎖

    排它鎖又稱寫鎖,若事務T對數據對象A加上X鎖,則只允許T讀取和修改A,其他任何事務都不能再對A加任何類型的鎖,直到T釋放A上的鎖。這就保證了其他事務在T釋放A上的鎖之前不能再讀取和修改A
    共享鎖又稱讀鎖,若事務T對數據對象A加上S鎖,則事務T可以讀A但不能修改A,其他事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。這就保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何的修改。

    一級封鎖協議:事務T在修改數據R之前必須先對其加X鎖,直到事務結束才釋放,這里的事務結束包括正常結束COMMIT和非正常結束ROLLBACK
    一級封鎖協議可以防止丟失修改,并保證事務T是可恢復的
    在一級鎖協議中,如果僅僅是讀數據不對其進行修改,是不需要加鎖的,所以它不能保證可重復讀和不讀臟數據

    二級封鎖協議:一級鎖協議加上事務T在讀取數據R之前必須先對其加S鎖,讀完后即可釋放S鎖
    二級封鎖協議除了防止丟失修改,還可以進一步防止讀“臟”數據
    在二級鎖協議中,由于讀完數據后即可釋放S鎖,所以它不能保證可重復讀


    三級鎖協議:一級封鎖協議加上事務T在讀取數據R之前必須對其加S鎖,直到事務結束才釋放S鎖
    三級封鎖協議除防止了丟失修改和不讀“臟”數據外,還進一步防止了不可重復讀



    Spring聲明式事務讓我們從復雜的事務處理中得到解脫。使得我們再也無需要去處理獲得連接、關閉連接、事務提交和回滾等這些操作。再也無需要我們在與事務相關的方法中處理大量的try…catch…finally代碼。
    我們在使用Spring聲明式事務時,有一個非常重要的概念就是事務屬性。事務屬性通常由事務的傳播行為,事務的隔離級別,事務的超時值和事務只讀標志組成。我們在進行事務劃分時,需要進行事務定義,也就是配置事務的屬性。
    Spring在TransactionDefinition接口中定義這些屬性,以供PlatfromTransactionManager使用, PlatfromTransactionManager是spring事務管理的核心接口。
    Java代碼 復制代碼
    1. TransactionDefinition   
    2. public interface TransactionDefinition {   
    3.     int getPropagationBehavior();   
    4.     int getIsolationLevel();   
    5.     int getTimeout();   
    6.     boolean isReadOnly();   
    7. }  


    getTimeout()方法,它返回事務必須在多少秒內完成。
    isReadOnly(),事務是否只讀,事務管理器能夠根據這個返回值進行優化,確保事務是只讀的。
    getIsolationLevel()方法返回事務的隔離級別,事務管理器根據它來控制另外一個事務可以看到本事務內的哪些數據。

    在TransactionDefinition接口中定義了五個不同的事務隔離級別
    ISOLATION_DEFAULT 這是一個PlatfromTransactionManager默認的隔離級別,使用數據庫默認的事務隔離級別.另外四個與JDBC的隔離級別相對應
    ISOLATION_READ_UNCOMMITTED 這是事務最低的隔離級別,它充許別外一個事務可以看到這個事務未提交的數據。這種隔離級別會產生臟讀,不可重復讀和幻像讀。
    例如:
    Mary的原工資為1000,財務人員將Mary的工資改為了8000,但未提交事務
    Java代碼 復制代碼
    1. Connection con1 = getConnection();   
    2. con.setAutoCommit(false);   
    3. update employee set salary = 8000 where empId ="Mary";  

    與此同時,Mary正在讀取自己的工資
    Java代碼 復制代碼
    1. Connection con2 = getConnection();   
    2. select   salary from employee where empId ="Mary";   
    3. con2.commit();  


    Mary發現自己的工資變為了8000,歡天喜地!
    而財務發現操作有誤,而回滾了事務,Mary的工資又變為了1000
    Java代碼 復制代碼
    1. //con1   
    2.    con1.rollback();  

    像這樣,Mary記取的工資數8000是一個臟數據。

    ISOLATION_READ_COMMITTED 保證一個事務修改的數據提交后才能被另外一個事務讀取。另外一個事務不能讀取該事務未提交的數據。這種事務隔離級別可以避免臟讀出現,但是可能會出現不可重復讀和幻像讀。

    ISOLATION_REPEATABLE_READ 這種事務隔離級別可以防止臟讀,不可重復讀。但是可能出現幻像讀。它除了保證一個事務不能讀取另一個事務未提交的數據外,還保證了避免下面的情況產生(不可重復讀)。

    在事務1中,Mary 讀取了自己的工資為1000,操作并沒有完成
    Java代碼 復制代碼
    1. con1 = getConnection();   
    2. select salary from employee empId ="Mary";  


    在事務2中,這時財務人員修改了Mary的工資為2000,并提交了事務.
    Java代碼 復制代碼
    1. con2 = getConnection();   
    2. update employee set salary = 2000;   
    3. con2.commit();  


    在事務1中,Mary 再次讀取自己的工資時,工資變為了2000
    Java代碼 復制代碼
    1. //con1   
    2. select salary from employee empId ="Mary";  


    在一個事務中前后兩次讀取的結果并不致,導致了不可重復讀。
    使用ISOLATION_REPEATABLE_READ可以避免這種情況發生。

    ISOLATION_SERIALIZABLE 這是花費最高代價但是最可靠的事務隔離級別。事務被處理為順序執行。除了防止臟讀,不可重復讀外,還避免了幻像讀。

    目前工資為1000的員工有10人。
    事務1,讀取所有工資為1000的員工。
    Java代碼 復制代碼
    1. con1 = getConnection();   
    2. Select * from employee where salary =1000;  
    共讀取10條記錄

    這時另一個事務向employee表插入了一條員工記錄,工資也為1000
    Java代碼 復制代碼
    1. con2 = getConnection();   
    2. Insert into employee(empId,salary) values("Lili",1000);   
    3. con2.commit();  


    事務1再次讀取所有工資為1000的員工
    Java代碼 復制代碼
    1. //con1   
    2. select * from employee where salary =1000;  


    共讀取到了11條記錄,這就產生了幻像讀。
    ISOLATION_SERIALIZABLE能避免這樣的情況發生。但是這樣也耗費了最大的資源。

    getPropagationBehavior()返回事務的傳播行為,由是否有一個活動的事務來決定一個事務調用。

    在TransactionDefinition接口中定義了七個事務傳播行為

    PROPAGATION_REQUIRED 如果存在一個事務,則支持當前事務。如果沒有事務則開啟一個新的事務。

    Java代碼 復制代碼
    1. //事務屬性 PROPAGATION_REQUIRED   
    2. methodA{   
    3. ……   
    4. methodB();   
    5. ……   
    6. }   
    7.   
    8. //事務屬性 PROPAGATION_REQUIRED   
    9. methodB{   
    10.     ……   
    11. }  


    使用spring聲明式事務,spring使用AOP來支持聲明式事務,會根據事務屬性,自動在方法調用之前決定是否開啟一個事務,并在方法執行之后決定事務提交或回滾事務。

    單獨調用methodB方法

    Java代碼 復制代碼
    1. main{   
    2.    metodB();   
    3. }  


    相當于

    Java代碼 復制代碼
    1. Main{   
    2. Connection con=null;   
    3.   
    4.     rry{   
    5.        con = getConnection();   
    6.        con.setAutoCommit(false);   
    7. //方法調用   
    8. methodB();   
    9. //提交事務   
    10. con.commit();   
    11. }   
    12. Catch(RuntimeException ex){   
    13.   //回滾事務   
    14.    con.rollback();     
    15. }   
    16. finally{   
    17.   //釋放資源   
    18.    closeCon();   
    19. }   
    20. }  


    Spring保證在methodB方法中所有的調用都獲得到一個相同的連接。在調用methodB時,沒有一個存在的事務,所以獲得一個新的連接,開啟了一個新的事務。

    單獨調用MethodA時,在MethodA內又會調用MethodB.

    執行效果相當于

    Java代碼 復制代碼
    1. main{   
    2.     Connection con = null;   
    3.    try{   
    4.        con = getConnection();   
    5.        methodA();   
    6.        con.commit();   
    7. }   
    8. cathc(RuntimeException ex){   
    9. con.rollback();   
    10. }   
    11. finally{   
    12.    closeCon();   
    13. }   
    14. }  


    調用MethodA時,環境中沒有事務,所以開啟一個新的事務.
    當在MethodA中調用MethodB時,環境中已經有了一個事務,所以methodB就加入當前事務。

    PROPAGATION_SUPPORTS 如果存在一個事務,支持當前事務。如果沒有事務,則非事務的執行。但是對于事務同步的事務管理器,PROPAGATION_SUPPORTS與不使用事務有少許不同。

    Java代碼 復制代碼
    1. //事務屬性 PROPAGATION_REQUIRED   
    2. methodA(){   
    3.    methodB();   
    4. }   
    5.   
    6. //事務屬性 PROPAGATION_SUPPORTS   
    7. methodB(){   
    8.    ……   
    9. }  


    單純的調用methodB時,methodB方法是非事務的執行的。
    當調用methdA時,methodB則加入了methodA的事務中,事務地執行。

    PROPAGATION_MANDATORY 如果已經存在一個事務,支持當前事務。如果沒有一個活動的事務,則拋出異常。

    Java代碼 復制代碼
    1. //事務屬性 PROPAGATION_REQUIRED   
    2. methodA(){   
    3.    methodB();   
    4. }   
    5.   
    6. //事務屬性 PROPAGATION_MANDATORY   
    7. methodB(){   
    8.    ……   
    9. }  


    當單獨調用methodB時,因為當前沒有一個活動的事務,則會拋出異常
    throw new IllegalTransactionStateException("Transaction propagation 'mandatory' but no existing transaction found");

    當調用methodA時,methodB則加入到methodA的事務中,事務地執行。

    PROPAGATION_REQUIRES_NEW 總是開啟一個新的事務。如果一個事務已經存在,則將這個存在的事務掛起。

    Java代碼 復制代碼
    1. //事務屬性 PROPAGATION_REQUIRED   
    2. methodA(){   
    3.    doSomeThingA();   
    4. methodB();   
    5. doSomeThingB();   
    6. }   
    7.   
    8. //事務屬性 PROPAGATION_REQUIRES_NEW   
    9. methodB(){   
    10.    ……   
    11. }  


    當單獨調用methodB時,相當于把methodB聲明為REQUIRED。開啟一個新的事務,事務地執行。

    當調用methodA時

    Java代碼 復制代碼
    1. main(){   
    2.    methodA();   
    3. }  

    情況有些大不一樣.相當于下面的效果。

    Java代碼 復制代碼
    1. main(){   
    2. TransactionManager tm = null;   
    3. try{   
    4.   //獲得一個JTA事務管理器   
    5.     tm = getTransactionManager();   
    6.     tm.begin();//開啟一個新的事務   
    7.     Transaction ts1 = tm.getTransaction();   
    8.     doSomeThing();   
    9.     tm.suspend();//掛起當前事務   
    10.    try{   
    11.       tm.begin();//重新開啟第二個事務   
    12.       Transaction ts2 = tm.getTransaction();   
    13.       methodB();   
    14.       ts2.commit();//提交第二個事務   
    15.         
    16.     }   
    17.    Catch(RunTimeException ex){   
    18.       ts2.rollback();//回滾第二個事務   
    19.    }   
    20.   finally{   
    21.     //釋放資源   
    22.    }   
    23.    //methodB執行完后,復恢第一個事務   
    24.     tm.resume(ts1);   
    25. doSomeThingB();   
    26.     ts1.commit();//提交第一個事務   
    27. }   
    28. catch(RunTimeException ex){   
    29.    ts1.rollback();//回滾第一個事務   
    30. }   
    31. finally{   
    32.   //釋放資源   
    33. }   
    34. }  


    在這里,我把ts1稱為外層事務,ts2稱為內層事務。從上面的代碼可以看出,ts2與ts1是兩個獨立的事務,互不相干。Ts2是否成功并不依賴于ts1。如果methodA方法在調用methodB方法后的doSomeThingB方法失敗了,而methodB方法所做的結果依然被提交。而除了methodB之外的其它代碼導致的結果卻被回滾了。
    使用PROPAGATION_REQUIRES_NEW,需要使用JtaTransactionManager作為事務管理器。

    PROPAGATION_NOT_SUPPORTED 總是非事務地執行,并掛起任何存在的事務。

    Java代碼 復制代碼
    1. //事務屬性 PROPAGATION_REQUIRED   
    2. methodA(){   
    3.    doSomeThingA();   
    4. methodB();   
    5. doSomeThingB();   
    6. }   
    7.   
    8. //事務屬性 PROPAGATION_NOT_SUPPORTED   
    9. methodB(){   
    10.    ……   
    11. }  


    當單獨調用methodB時,不啟用任何事務機制,非事務地執行。
    當調用methodA時,相當于下面的效果

    Java代碼 復制代碼
    1. main(){   
    2. TransactionManager tm = null;   
    3. try{   
    4.   //獲得一個JTA事務管理器   
    5.     tm = getTransactionManager();   
    6.     tm.begin();//開啟一個新的事務   
    7.     Transaction ts1 = tm.getTransaction();   
    8.     doSomeThing();   
    9.     tm.suspend();//掛起當前事務   
    10.       methodB();   
    11.    //methodB執行完后,復恢第一個事務   
    12.     tm.resume(ts1);   
    13. doSomeThingB();   
    14.     ts1.commit();//提交第一個事務   
    15. }   
    16. catch(RunTimeException ex){   
    17.    ts1.rollback();//回滾第一個事務   
    18. }   
    19. finally{   
    20.   //釋放資源   
    21. }   
    22. }  

    使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作為事務管理器。

    PROPAGATION_NEVER 總是非事務地執行,如果存在一個活動事務,則拋出異常

    Java代碼 復制代碼
    1. //事務屬性 PROPAGATION_REQUIRED   
    2. methodA(){   
    3.    doSomeThingA();   
    4. methodB();   
    5. doSomeThingB();   
    6. }   
    7.   
    8. //事務屬性 PROPAGATION_NEVER   
    9. methodB(){   
    10.    ……   
    11. }  

    單獨調用methodB,則非事務的執行。
    調用methodA則會拋出異常
    throw new IllegalTransactionStateException(
    "Transaction propagation 'never' but existing transaction found");


    PROPAGATION_NESTED如果一個活動的事務存在,則運行在一個嵌套的事務中. 如果沒有活動事務, 則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執行

    這是一個嵌套事務,使用JDBC 3.0驅動時,僅僅支持DataSourceTransactionManager作為事務管理器。需要JDBC 驅動的java.sql.Savepoint類。有一些JTA的事務管理器實現可能也提供了同樣的功能。

    使用PROPAGATION_NESTED,還需要把PlatformTransactionManager的nestedTransactionAllowed屬性設為true;
    而nestedTransactionAllowed屬性值默認為false;

    Java代碼 復制代碼
    1. //事務屬性 PROPAGATION_REQUIRED   
    2. methodA(){   
    3.    doSomeThingA();   
    4. methodB();   
    5. doSomeThingB();   
    6. }   
    7.   
    8. //事務屬性 PROPAGATION_NESTED   
    9. methodB(){   
    10.    ……   
    11. }  


    如果單獨調用methodB方法,則按REQUIRED屬性執行。

    如果調用methodA方法,相當于下面的效果

    Java代碼 復制代碼
    1. main(){   
    2. Connection con = null;   
    3. Savepoint savepoint = null;   
    4. try{   
    5.    con = getConnection();   
    6.    con.setAutoCommit(false);   
    7.    doSomeThingA();   
    8.    savepoint = con2.setSavepoint();   
    9.   try  
    10.        methodB();   
    11.    }catch(RuntimeException ex){   
    12.       con.rollback(savepoint);   
    13.    }   
    14.   finally{   
    15.     //釋放資源   
    16.    }   
    17.   
    18.    doSomeThingB();   
    19.    con.commit();   
    20. }   
    21. catch(RuntimeException ex){   
    22.    con.rollback();   
    23. }   
    24. finally{   
    25.   //釋放資源   
    26. }   
    27. }  

    當methodB方法調用之前,調用setSavepoint方法,保存當前的狀態到savepoint。如果methodB方法調用失敗,則恢復到之前保存的狀態。但是需要注意的是,這時的事務并沒有進行提交,如果后續的代碼(doSomeThingB()方法)調用失敗,則回滾包括methodB方法的所有操作。

    嵌套事務一個非常重要的概念就是內層事務依賴于外層事務。外層事務失敗時,會回滾內層事務所做的動作。而內層事務操作失敗并不會引起外層事務的回滾

    PROPAGATION_NESTED 與PROPAGATION_REQUIRES_NEW的區別:它們非常類似,都像一個嵌套事務,如果不存在一個活動的事務,都會開啟一個新的事務。使用PROPAGATION_REQUIRES_NEW時,內層事務與外層事務就像兩個獨立的事務一樣,一旦內層事務進行了提交后,外層事務不能對其進行回滾。兩個事務互不影響。兩個事務不是一個真正的嵌套事務。同時它需要JTA事務管理器的支持。
    使用PROPAGATION_NESTED時,外層事務的回滾可以引起內層事務的回滾。而內層事務的異常并不會導致外層事務的回滾,它是一個真正的嵌套事務。DataSourceTransactionManager使用savepoint支持PROPAGATION_NESTED時,需要JDBC 3.0以上驅動及1.4以上的JDK版本支持。其它的JTA TrasactionManager實現可能有不同的支持方式。

    PROPAGATION_REQUIRED應該是我們首先的事務傳播行為。它能夠滿足我們大多數的事務需求。


    posted on 2009-08-01 14:17 Frank_Fang 閱讀(2752) 評論(3)  編輯  收藏 所屬分類: SSH+JQuery+DWR

    評論:
    # re: 【轉】詳解spring事務屬性 2009-08-01 19:17 | Frank_Fang
    關于事務傳播屬性還有一個常見的誤解:

    java 代碼

    class A{

    //事務屬性 PROPAGATION_REQUIRED

    methodA(){

    ......
    ......

    methodB();
    }

    //事務屬性 PROPAGATION_REQUIRES_NEW

    methodB(){
    .......
    }

    }

    此時外部程序對methodA的調用只會發起一個事務,methodB的PROPAGATION_REQUIRES_NEW屬性不會起作用
    因為methodA是在內部對methodB直接調用,AOP聲明式事務自然就不起作用了
    所以外部程序對methodB的調用仍然是PROPAGATION_REQUIRES_NEW的   回復  更多評論
      
    # re: 【轉】詳解spring事務屬性 2009-08-26 00:10 | Frank_Fang
    二、Isolation Level(事務隔離等級):
    1、Serializable:最嚴格的級別,事務串行執行,資源消耗最大;
    2、REPEATABLE READ:保證了一個事務不會修改已經由另一個事務讀取但未提交(回滾)的數據。避免了“臟讀取”和“不可重復讀取”的情況,但是帶來了更多的性能損失。
    3、READ COMMITTED:大多數主流數據庫的默認事務等級,保證了一個事務不會讀到另一個并行事務已修改但未提交的數據,避免了“臟讀取”。該級別適用于大多數系統。
    4、Read Uncommitted:保證了讀取過程中不會讀取到非法數據。隔離級別在于處理多事務的并發問題。
    我們知道并行可以提高數據庫的吞吐量和效率,但是并不是所有的并發事務都可以并發運行,這需要查看數據庫教材的可串行化條件判斷了。
    這里就不闡述。
    我們首先說并發中可能發生的3中不討人喜歡的事情
    1: Dirty reads--讀臟數據。也就是說,比如事務A的未提交(還依然緩存)的數據被事務B讀走,如果事務A失敗回滾,會導致事務B所讀取的的數據是錯誤的。
    2: non-repeatable reads--數據不可重復讀。比如事務A中兩處讀取數據-total-的值。在第一讀的時候,total是100,然后事務B就把total的數據改成200,事務A再讀一次,結果就發現,total竟然就變成200了,造成事務A數據混亂。
    3: phantom reads--幻象讀數據,這個和non-repeatable reads相似,也是同一個事務中多次讀不一致的問題。但是non-repeatable reads的不一致是因為他所要取的數據集被改變了(比如total的數據),但是phantom reads所要讀的數據的不一致卻不是他所要讀的數據集改變,而是他的條件數據集改變。比如Select account.id where account.name="ppgogo*",第一次讀去了6個符合條件的id,第二次讀取的時候,由于事務b把一個帳號的名字由"dd"改成"ppgogo1",結果取出來了7個數據。 Dirty reads non-repeatable reads phantom reads
    Serializable 不會 不會 不會
    REPEATABLE READ 不會 不會 會
    READ COMMITTED 不會 會 會
    Read Uncommitted 會 會 會

    三、readOnly
    事務屬性中的readOnly標志表示對應的事務應該被最優化為只讀事務。這是一個最優化提示。在一些情況下,一些事務策略能夠起到顯著的最優化效果,例如在使用Object/Relational映射工具(如:Hibernate或TopLink)時避免dirty checking(試圖“刷新”)。

    四、Timeout 在事務屬性中還有定義“timeout”值的選項,指定事務超時為幾秒。在JTA中,這將被簡單地傳遞到J2EE服務器的事務協調程序,并據此得到相應的解釋。
      回復  更多評論
      
    # re: 【轉】詳解spring事務屬性 2009-08-26 00:30 | Frank_Fang
    數據庫提供了四種事務隔離級別, 不同的隔離級別采用不同的鎖類開來實現.

    在四種隔離級別中, Serializable的級別最高, Read Uncommited級別最低.

    大多數數據庫的默認隔離級別為: Read Commited,如Sql Server , Oracle.

    少數數據庫默認的隔離級別為Repeatable Read, 如MySQL InnoDB存儲引擎


    Read Uncommited :讀未提交數據( 會出現臟讀,不可重復讀,幻讀)

    Read Commited :讀已提交的數據(會出現不可重復讀,幻讀)

    Repeatable Read :可重復讀(會出現幻讀)

    Serializable :串行化


    丟失 更新 :
    當兩個或多個事務選擇同一行,然后基于最初選定的值更新該行時,會發生丟失更新問題。每個事務都不知道其它事務的存在。最后的更新將重寫由其它事務所做的更新,這將導致數據丟失。   
    例:
    事務A和事務B同時修改某行的值,
    1.事務A將數值改為1并提交
    2.事務B將數值改為2并提交。
    這時數據的值為2,事務A所做的更新將會丟失。
    解決辦法:對行加鎖,只允許并發一個更新事務。



    臟讀: 一個事務讀到另一個事務未提交的更新數據

    例:


    1.Mary的原工資為1000, 財務人員將Mary的工資改為了8000(但未提交事務)
    2.Mary讀取自己的工資 ,發現自己的工資變為了8000,歡天喜地!
    3.而財務發現操作有誤,回滾了事務,Mary的工資又變為了1000, 像這樣,Mary記取的工資數8000是一個臟數據。



    不可重復讀: 在同一個事務中,多次讀取同一數據,返回的結果有所不同. 換句話說就是,后續讀取可以讀到另一個事務已提交的更新數據. 相反"可重復讀"在同一事務多次讀取數據時,能夠保證所讀數據一樣,也就是后續讀取不能讀到另一事務已提交的更新數據.

    例:


    1.在事務1中,Mary 讀取了自己的工資為1000,操作并沒有完成
    2.在事務2中,這時財務人員修改了Mary的工資為2000,并提交了事務.
    3.在事務1中,Mary 再次讀取自己的工資時,工資變為了2000
    解決辦法:如果只有在修改事務完全提交之后才可以讀取數據,則可以避免該問題。



    幻讀: 一個事務讀取到另一個事務已提交的insert數據.

    例:

    第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的全部數據行。同時 (此時第一事務還未提交) ,第二個事務向表中插入一行新數據。這時第一個事務再去讀取表時,發現表中還有沒有修改的數據行,就好象發生了幻覺一樣。

      回復  更多評論
      
    主站蜘蛛池模板: 亚洲一级大黄大色毛片| 亚洲AV无码国产一区二区三区| 免费播放美女一级毛片| 黄页网站免费观看| 亚洲欧洲日产国码二区首页| 亚洲成_人网站图片| 国产精品亚洲专区无码唯爱网| 九九九精品视频免费| 麻花传媒剧在线mv免费观看| 久久亚洲伊人中字综合精品| 免费人成在线观看视频高潮| 亚洲午夜福利717| 在线观看片免费人成视频无码| 亚洲日本一区二区三区在线| av永久免费网站在线观看| 亚洲精品~无码抽插| 婷婷亚洲综合五月天小说在线| 国产一级淫片视频免费看| 色噜噜狠狠色综合免费视频 | 一级毛片a女人刺激视频免费| 亚洲精品偷拍视频免费观看 | 亚洲a级片在线观看| 毛片高清视频在线看免费观看| 亚洲区小说区图片区QVOD| 免费成人在线电影| 亚洲成电影在线观看青青| 成年私人影院免费视频网站| 亚洲最大黄色网站| 天天摸天天操免费播放小视频| 美女黄频免费网站| 亚洲精品狼友在线播放| 在免费jizzjizz在线播| 亚洲av无码日韩av无码网站冲 | 亚洲精品自产拍在线观看动漫| 国产精品免费精品自在线观看| 亚洲人成欧美中文字幕| 亚洲精品无码永久在线观看| 国产一精品一AV一免费| 国产午夜亚洲精品| 亚洲乱亚洲乱妇无码麻豆| 97免费人妻无码视频|