☆Springトランザクションメカニズムの詳細

8323 ワード

Springトランザクションメカニズムは主に を含み、ここでは宣言トランザクションに重点を置いて説明し、プログラミングトランザクションは実際の開発で広く使用されず、学習の参考に供される.
Spring宣言トランザクションは、複雑なトランザクションから解放されます. 、 、 ですトランザクションに関連するメソッドで大量のtry...catch...finallyコードを処理する必要はありません.Spring宣言トランザクションを使用する場合、トランザクション属性という非常に重要な概念があります. , , .トランザクションの分割には、トランザクション定義、すなわちトランザクションのプロパティを構成する必要があります.
以下、事務の4つの属性について詳しく説明します.
Springは、PlatfromTransactionManagerで使用するためのTransactionDefinitionインタフェースでこれらのプロパティを定義します.PlatfromTransactionManager Spring .
public interface TransactionDefinition { 
  int getPropagationBehavior(); //         。 
  int getIsolationLevel(); //         ,                              。 
  int getTimeout(); //             。 
  boolean isReadOnly(); //      ,                  ,        。 
}
  • TransactionDefinitionインタフェースで定義された5つの独立性レベル:
  • ISOLATION_DEFAULT PlatfromTransactionManager 、データベースのデフォルトのトランザクション独立性レベルを使用します.他の4つはJDBCの独立性レベルに対応しています.ISOLATION_READ_UNCOMMITTED は、このトランザクションがコミットされていないデータを別のトランザクションで見ることができることを許可します.この独立性レベルでは、汚れた読み取り、重複しない読み取り、幻の読み取りが発生します.ISOLATION_READ_COMMITTED .別のトランザクションでは、トランザクションがコミットされていないデータを読み取ることはできません.このトランザクション独立性レベルでは、汚れた読み取りは回避できますが、重複しない読み取りと幻の読み取りが発生する可能性があります.ISOLATION_REPEATABLE_READ , .しかし、幻読みが現れる可能性があります.これにより、1つのトランザクションが別のトランザクションでコミットされていないデータを読み取ることができないことを保証するほか、次の状況の発生を回避することが保証されます(重複して読むことはできません).ISOLATION_SERIALIZABLE 。トランザクションは、順次実行されるように処理される.汚れた読みを防止し、繰り返して読むことができないほか、幻の読みも避けられます.
  • TransactionDefinitionインタフェースでは、7つのトランザクション伝播動作が定義されています.
  • (1) PROPAGATION_REQUIRED , .トランザクションがない場合は、新しいトランザクションが開きます.
    //      PROPAGATION_REQUIRED 
    methodA { 
       …… 
       methodB();
       …… 
    }
    //      PROPAGATION_REQUIRED 
    methodB { 
       …… 
    }
    

    Spring宣言トランザクションを使用し、springはAOPを使用して宣言トランザクションをサポートします.トランザクションのプロパティに基づいて、メソッド呼び出しの前にトランザクションを開くかどうかを自動的に決定し、メソッドの実行後にトランザクションのコミットまたはロールバックを決定します.
    methodBメソッドを個別に呼び出します.
    main { 
       metodB(); 
    }
       
    Main {
       Connection con=null; 
       try{ 
         con = getConnection(); 
         con.setAutoCommit(false); 
         //    
         methodB(); 
         //    
         con.commit(); 
       } Catch(RuntimeException ex) { 
         //    
         con.rollback();   
       } finally { 
         //    
         closeCon(); 
       } 
    }
    

    Springは、methodBメソッド内のすべての呼び出しが同じ接続になることを保証します.methodBが呼び出されたとき、 , , .
    MethodAを単独で呼び出すと、MethodA内でMethoddBが呼び出されます.実行効果は次のとおりです.
    Main { 
       Connection con = null; 
       try { 
         con = getConnection(); 
         methodA(); 
         con.commit(); 
       } catch(RuntimeException ex) { 
         con.rollback(); 
       } finally { 
         closeCon(); 
       }  
    }
    

    MethodAを呼び出すと、環境にトランザクションがないため、新しいトランザクション MethodA MethodB , , methodB が開きます.
    (2)PROPAGATION_SUPPORTS , 。 , 。しかしトランザクション同期のトランザクションマネージャに対してPROPACATION_SUPPORTSは事務を使わないのとは少し違います.
    //      PROPAGATION_REQUIRED 
    methodA() {   
       methodB(); 
    }
    //      PROPAGATION_SUPPORTS 
    methodB() {
       ……
    }
    

    単純にmethodBを呼び出すと、methodBメソッドは非トランザクションで実行されます. methdA ,methodB methodA .
    (3) PROPAGATION_MANDATORY , 。 , .
    //      PROPAGATION_REQUIRED
    methodA() {
       methodB();
    }
    //     PROPAGATION_MANDATORY     
    methodB() {     
       ……
    }
    

    methodBが個別に呼び出されると、 , throw new IllegalTransactionStateException("Transaction propagation 'mandatory' but no existing transaction found");はmethodAが呼び出されると、methodAのトランザクションにmethodBが追加されて実行される.
    (4) PROPAGATION_REQUIRES_NEW .トランザクションがすでに存在する場合は、その存在するトランザクションを保留します.
    //     PROPAGATION_REQUIRED 
    methodA() {    
       doSomeThingA(); 
       methodB(); 
       doSomeThingB(); 
    }
    //     PROPAGATION_REQUIRES_NEW 
    methodB() {
       …… 
    }
    
    main() {
       methodA(); 
    }
    

    次のようになります.
    main() {
       TransactionManager tm = null; 
       try {   
         //     JTA          
         tm = getTransactionManager();
         tm.begin(); 
         //         
         Transaction ts1 = tm.getTransaction();
         doSomeThing();     
         tm.suspend(); //            
         try {
           tm.begin();//                 
           Transaction ts2 = tm.getTransaction();       
           methodB();       
           ts2.commit();//            
         } catch(RunTimeException ex) {
            ts2.rollback(); //           
         } finally {      
            //     
         }
         // methodB    ,            
         tm.resume(ts1); 
         doSomeThingB();     
         ts1.commit();//         
       } catch(RunTimeException ex) {
         ts1.rollback();//         
       } finally {
         //     
       } 
    }
    

    ここで、ts1 ,ts2 を.上記のコードからts2 ts1 , 。Ts2 ts1がわかります.methodAメソッドがmethodBメソッドを呼び出した後のdoSomeThingBメソッドが失敗した場合、methodBメソッドの結果がコミットされます.methodB以外のコードによる結果はロールバックされた. PROPAGATION_REQUIRES_NEW, JtaTransactionManager .
    (5) PROPAGATION_NOT_SUPPORTED , .PROPAGATION_を使うNOT_SUPPORTEDは、JtaTransactionManagerをトランザクションマネージャとして使用する必要もあります.
    (6) PROPAGATION_NEVER , , ;
    (7) PROPAGATION_NESTED , . , TransactionDefinition.PROPAGATION_REQUIRED .これはネストされたトランザクションで、JDBC 3.0ドライバを使用する場合、DataSourceTransactionManagerのみがトランザクションマネージャとしてサポートされます.JDBCドライバのjava.sql.Savepointクラスが必要です.いくつかのJTAのトランザクションマネージャ実装も同様の機能を提供している可能性があります.PROPAGATION_を使うNESTEDでは、PlatformTransactionManagerのnestedTransactionAllowedプロパティをtrueに設定する必要があります.一方、nestedTransactionAllowedプロパティの値はfalseにデフォルト設定されています.
    //      PROPAGATION_REQUIRED 
    methodA() {
       doSomeThingA();
       methodB();
       doSomeThingB(); 
    }
    //     PROPAGATION_NESTED 
    methodB() {
       …… 
    }
    
    methodB , REQUIRED .methodAメソッドを呼び出すと、次の効果に相当します.
    main() { 
        Connection con = null; 
        Savepoint savepoint = null; 
        try{
          con = getConnection();
          con.setAutoCommit(false);
          doSomeThingA();
          savepoint = con2.setSavepoint();
          try{
              methodB();
          } catch(RuntimeException ex) {
              con.rollback(savepoint);
          } finally {
              //       
          }
          doSomeThingB();
          con.commit(); 
        } catch(RuntimeException ex) {
          con.rollback(); 
        } finally {
          //    
        } 
    }
    

    methodBメソッドが呼び出される前にsetSavepointメソッドを呼び出し、現在のステータスをsavepointに保存します.methodBメソッドの呼び出しに失敗した場合は、以前に保存した状態に戻ります.ただし、この場合のトランザクションはコミットされず、後続のコード(doSomeThingB()メソッド)呼び出しに失敗した場合、methodBメソッドを含むすべての操作がロールバックされることに注意してください. 。 , 。 .
    PROPAGATION_NESTEDとPROPAGATION_REQUIRES_NEWの違い:
    これらは非常に類似しており、ネストされたトランザクションのように、アクティブなトランザクションが存在しない場合は、新しいトランザクションが開きます. PROPAGATION_REQUIRES_NEW , .内部取引がコミットされると、外部取引はロールバックできません.2つのトランザクションは互いに影響しない.2つのトランザクションは、真のネストされたトランザクションではありません.同時にJTAトランザクションマネージャのサポートが必要です.
    PROPAGATION_を使うNESTEDの場合、 。 , です.DataSourceTransactionManager savepointを使用してPROPAGATION_をサポートNESTEDでは、JDBC 3.0以上のドライバおよび1.4以上のJDKバージョンのサポートが必要です.他のJTA TransactionManagerの実装では、サポート方法が異なる場合があります.PROPAGATION_REQUIRES_NEW , " " .このトランザクションは、外部トランザクションに依存せずに完全にcommitedまたはrolled backされ、独自の独立範囲、独自のロックなどを有します.内部トランザクションが実行を開始すると、外部トランザクションは停止され、内務トランザクションが終了すると、外部トランザクションは実行されます.
    一方、PROPAGATION_NESTEDは、すでに存在するトランザクションの真のサブトランザクションであるネストされたトランザクションを開始します. , savepoint. , savepoint.潜在的なトランザクションは、外部トランザクションの一部であり、外部トランザクションが終了した後にのみコミットされます.
    これにより、PROPAGATION_REQUIRES_NEWとPROPAGATION_NESTEDの最大の違いは、PROPAGATION_REQUIRES_NEW , PROPAGATION_NESTED , commit, commit, roll backです.PROPAGATION_REQUIRDは私たちの最初のトランザクション伝播行為であるべきです.ほとんどのトランザクション要件を満たすことができます.