天天看點

bboss aop 實踐(6) 聲明式事務管理

bboss 項目下載下傳位址:

https://sourceforge.net/project/showfiles.php?group_id=238653

Bboss aop作為一個輕量級的aop架構,一個非常重要的功能就是結合bboss persistent架構實作資料庫聲明式事務管理功能,本節就詳細地介紹這個功能。

在介紹聲明式事務管理功能之前,先簡單介紹一下bboss persistent持久層架構提供的事務管理功能,詳細的情況請參考部落格文章《bboss persistent事務管理介紹》。

bboss persistent持久層架構事務管理功能介紹

bboss persistent架構提供了四種類型的事務管理類型,業務元件可以根據自己的需要進行相應的選擇,這四種類型分别是:

a.    必須建立新的事務(NEW_TRANSACTION)

b.    有事務就加入目前事務,沒有就不建立事務(MAYBE_TRANSACTION)

c.    有事務就加入目前事務,沒有就建立事務(REQUIRED_TRANSACTION)(預設情況)

d.    沒有事務(NO_TRANSACTION)

Bboss persistent的事務管理功能主要是由元件

com.frameworkset.orm.transaction.TransactionManager提供。那麼應用程式可以根據自己的采用可程式設計的方式來實作自己的資料庫事務管理,也可以通過聲明式的方式來進行事務管理。可程式設計的方式方式又包含兩種情況:

a.    直接使用TransactionManager元件來開啟事務、送出/復原事務

b.       采用事務管理模闆元件來管理事務,bboss persistent持久層架構提供了以下元件來實作這個功能:

         com.frameworkset.common.poolman.JDBCTemplate  不帶傳回值模闆接口

     com.frameworkset.common.poolman.JDBCValueTemplate  帶傳回值的模闆接

     com.frameworkset.common.poolman.TemplateDBUtil  提供執行上述兩種模闆接口的事務上下文環境,具體的使用方法請參考部落格文章《bboss persistent事務管理介紹》和《bboss persistent持久層架構元件介紹》這裡就不多說了。

聲明式事務管理

了解了bboss persistent持久層架構的事務管理功能後,我們就來詳細地介紹bboss aop架構提供的聲明式事務管理功能。bboss aop架構為聲明式事務管理定義了一個資料庫事務管理攔截器:

com.chinacreator.spi.interceptor.TransactionInterceptor

通過該攔截器來管理業務元件中的資料庫事務,這樣應用程式隻需要在bboss aop的配置檔案中聲明相應類型的資料庫事務即可,而不需要在業務元件中顯示地管理資料庫事務。可以在業務方法中使用所有的bboss persistent持久層架構中的所有元件來操作資料庫,這些操作都将在聲明的事務環境中執行。

下面是聲明式事務配置的文法:

transactions(method+)   

    method(param*,rollbackexceptions?)

    method-attributelist{

       name-方法名稱,name和pattern不能同時出現

       pattern-比對方法名稱的正規表達式

       txtype-需要控制的事務類型,取值範圍:

                  NEW_TRANSACTION,

                  REQUIRED_TRANSACTION,

                  MAYBE_TRANSACTION,

                  NO_TRANSACTION

    }

    param(pcdata)

    param-attributelist{

       type-

    rollbackexceptions(exception+) 

    exception(pcdata)

    exception-attributelist{

       class-

       type-IMPLEMENTS,INSTANCEOF

}

隻需要在配置檔案中配置需要進行事務管理的業務方法即可,配置的内容包括:

l         方法名稱和方法的參數(必須)

l         聲明的方法的事務類型(可選,預設為REQUIRED_TRANSACTION)

l         復原事務的異常(可選,不配置時表示所有的異常都會復原事務)

除了配置了復原異常外,還可以通過type屬性配置復原異常的是否包含異常類型的子異常類型:

  IMPLEMENTS—不包含

  INSTANCEOF—包含

聲明式事務管理使用執行個體

定義業務元件

在元件方法中操作資料庫,這個方法将在配置檔案中聲明事務

元件接口

package com.chinacreator.spi.transaction;

public interface AI {

    public void testTXInvoke(String msg)throws Exception;

    public void testTXInvoke() throws Exception;

    public void testNoTXInvoke()throws Exception;

    public String testTXInvokeWithReturn()throws Exception;

    public String testTXInvokeWithException() throws Exception;

    public void testSameName()throws Exception;

    public void testSameName(String msg)throws Exception;

    public void testSameName1()throws Exception;

    public void testSameName1(String msg)throws Exception;

    /**

     * 混合異常測試,即包含執行個體異常,也包含子類和執行個體異常

     * 所有的異常都将導緻事務復原

     */

    public void testTXWithSpecialExceptions(String type) throws Exception;

     * 隻要是特定執行個體的異常就會復原

     * @param type

     * @throws Exception

    public void testTXWithInstanceofExceptions(String type) throws Exception;

     * 隻有異常本身的執行個體異常才觸發事務的復原

    public void testTXWithImplementsofExceptions(String type) throws Exception;

    public void testPatternTX1(String type) throws Exception;

    public void testPatternTX2(String type) throws Exception;

    public void testPatternTX3(String type) throws Exception;

    public void testPatternTX4(String type) throws Exception;

    public void testSystemException() throws Exception;

元件實作

import java.sql.SQLException;

import com.frameworkset.common.poolman.DBUtil;

public class A1 implements AI{

    public void testTXInvoke(String msg) throws Exception {

       System.out.println("A1:" + msg);

       DBUtil db = new DBUtil();

       System.out.println("db.getNumIdle():" +db.getNumIdle());

       System.out.println("db.getNumActive():" +db.getNumActive());

       String id = db.getNextStringPrimaryKey("test");

       db.executeInsert("insert into test(id,name) values('"+id+"','testTXInvoke(" + msg +")')");

       db.executeInsert("insert into test1(A) values('testTXInvoke(" + msg +")')");

       System.out.println("1db.getNumActive():" +db.getNumActive());

       System.out.println("1db.getNumIdle():" +db.getNumIdle());

    public void testTXInvoke() throws SQLException {

       System.out.println("A1.testTXInvoke():no param");

       db.executeInsert("insert into test(id,name) values('"+id+"','testTXInvoke()')");

       db.executeInsert("insert into test1(A) values('testTXInvoke')");

    public void testNoTXInvoke()

    {

       System.out.println("A1:NoTXInvoke");

       try {

           String id = db.getNextStringPrimaryKey("test");

           db.executeInsert("insert into test(id,name) values('"+id+"','testTXInvoke()')");

           db.executeInsert("insert into test1(A) values('testTXInvoke()')");

       } catch (SQLException e) {

           // TODO Auto-generated catch block

           e.printStackTrace();

       }

    public String testTXInvokeWithReturn() {

       System.out.println("call A1.testTXInvokeWithReturn()");

           db.executeInsert("insert into test(id,name) values('"+id+"','testTXInvokeWithReturn()')");

           db.executeInsert("insert into test1(A) values('testTXInvokeWithReturn()')");

       return "return is A1";

     * 隻要抛出異常,事務就復原

    public String testTXInvokeWithException() throws Exception {

       System.out.println("call A1.testTXInvokeWithException()");

       db.executeInsert("insert into test(id,name) values('"+id+"','testTXInvokeWithException()')");

       if(true)

           throw new Exception1("A1 throw a exception");

       return "A1 exception find.";

    public void testSameName() throws SQLException {

       System.out.println("call A1.testSameName()");

       db.executeInsert("insert into test(id,name) values('"+id+"','testSameName()')");

    public void testSameName(String msg) throws SQLException {

       System.out.println("call A1.testSameName("+msg+")");

       db.executeInsert("insert into test(id,name) values('"+id+"','testSameName("+msg+")')");

    public void testSameName1() throws SQLException {

       System.out.println("call A1.testSameName1()");

       db.executeInsert("insert into test(id,name) values('"+id+"','testSameName1()')");

    public void testSameName1(String msg) throws SQLException {

       System.out.println("call A1.testSameName1(String msg):" + msg);

       db.executeInsert("insert into test(id,name) values('"+id+"','testSameName1("+msg+")')");

    public int testInt(int i) {

       System.out.println("call A1.testInt(int i):" + i);

       return i;

    public int testIntNoTX(int i) {

       System.out.println("call A1.testIntNoTX(int i):" + i);

       return i;    

    public void testTXWithSpecialExceptions(String type) throws Exception

       db.executeInsert("insert into test(id,name) values('"+id+"','testTXWithSpecialExceptions("+type+")')");

       //事務復原

       if(type.equals("IMPLEMENTS"))

       {

           throw new RollbackInstanceofException("IMPLEMENTS RollbackInstanceofException");

       if(type.equals("INSTANCEOF"))

           throw new SubRollbackInstanceofException("INSTANCEOF RollbackInstanceofException");

       if(type.equals("exception1"))

           throw new Exception1("IMPLEMENTS exception1");

       /**

        * 事務不會復原,沒有進行配置

        */

       if(type.equals("notxexception"))

           throw new Exception3("notxexception Exception3");

    public void testTXWithInstanceofExceptions(String type) throws Exception

       db.executeInsert("insert into test(id,name) values('"+id+"','testTXWithInstanceofExceptions(" + type + ")')");

        * 事務不會復原,送出

    public void testTXWithImplementsofExceptions(String type) throws Exception

       db.executeInsert("insert into test(id,name) values('"+id+"','testTXWithImplementsofExceptions(" + type + ")')");

       //事務不會復原,送出

    public void testPatternTX1(String type) throws Exception

       db.executeInsert("insert into test(id,name) values('"+id+"','testPatternTX1(" + type + ")')");

    public void testPatternTX2(String type) throws Exception

       db.executeInsert("insert into test(id,name) values('"+id+"','testPatternTX2(" + type + ")')");

    public void testPatternTX3(String type) throws Exception

       db.executeInsert("insert into test(id,name) values('"+id+"','testPatternTX3(" + type + ")')");

    public void testPatternTX4(String type) throws Exception

       db.executeInsert("insert into test(id,name) values('"+id+"','testPatternTX4(" + type + ")')");

     * 針對系統級别的異常,事務自動復原

     * 本方法聲明了事務復原異常

     * <method name="testSystemException">

              <rollbackexceptions>

                  <exception class="com.chinacreator.spi.transaction.RollbackInstanceofException"

                  type="IMPLEMENTS"/>

              </rollbackexceptions>

           </method>

           方法中抛出了系統級别的空指針異常,将導緻事務復原

    public void testSystemException() throws Exception

       db.executeInsert("insert into test(id,name) values('"+id+"','testSystemException()')");

//     throw new java.lang.NullPointerException("空指針異常。事務復原");

業務異常定義

public class Exception1 extends Exception {

    public Exception1(String msg)

       super(msg);

public class Exception3 extends Exception{

    public Exception3(String msg)

配置業務元件,配置業務方法的聲明式事務

建立xml配置檔案manager-transaction.xml,存放在包路徑com.chinacreator.spi.transaction下,檔案的内容如下:

<?xml version="1.0" encoding='gb2312'?>

<!--

聲明式事務方法配置檔案,包含正規表達式指定的方法名稱

-->

<manager-config>

    <manager id="tx.a" singlable="true" >

       <provider type="DB"         class="com.chinacreator.spi.transaction.A1" />

       <!-- <provider type="ldap" used="true"

           class="com.chinacreator.spi.tx.A2" /> -->

       <!-- 

           在下面的節點對provider的業務方法事務進行定義

           隻要将需要進行事務控制的方法配置在transactions中即可

       -->

       <transactions>

           <!--

              定義需要進行事務控制的方法

              屬性說明:

              name-方法名稱,可以是一個正規表達式,正規表達式的文法請參考jakarta-oro的相關文檔,如果使用

              正規表達式的情況時,則方法中聲明的方法參數将被忽略,但是復原異常有效。

              pattern-方法名稱的正規表達式比對模式,模式比對的順序受配置位置的影響,如果配置在後面或者中間,

                     那麼會先執行之前的方法比對,如果比對上了就不會對該模式方法進行比對了,否則執行比對操作。

                     如果比對上特定的方法名稱,那麼這個方法就是需要進行事務控制的方法

                     例如:模式testInt.*比對接口中以testInt開頭的任何方法

              txtype-需要控制的事務類型,取值範圍:

              NEW_TRANSACTION,

              REQUIRED_TRANSACTION,

              MAYBE_TRANSACTION,

              NO_TRANSACTION

           -->

           <method name="testTXInvoke" txtype="NEW_TRANSACTION">

              <param type="java.lang.String"/>

           </method>        

           <method name="testTXInvoke" txtype="REQUIRED_TRANSACTION"/>

           <method name="testTXInvokeWithReturn" txtype="REQUIRED_TRANSACTION"/>

           <method name="testTXInvokeWithException" txtype="MAYBE_TRANSACTION"/>    

           <method name="testSameName" txtype="NO_TRANSACTION"/>

           <method name="testSameName1">

           <!--             

                  定義使事務復原的異常,如果沒有明确聲明需要復原事務的異常,那麼當有異常發生時,事務管理架構将自動復原目前事務

                  class-異常的完整類路徑

                  type-是否檢測類型異常的子類控制辨別,

                  IMPLEMENTS隻檢測異常類本身,忽略異常類的子類;

                  INSTANCEOF檢查異常類本省及其所有子類

              -->

           <method name="testTXWithSpecialExceptions">

                  type="INSTANCEOF"/>

                  <exception class="com.chinacreator.spi.transaction.Exception1"

           <method name="testTXWithInstanceofExceptions">

           <method name="testTXWithImplementsofExceptions">

                  如果涉及的方法名稱是一個正規表達式的比對模式,則無需配置方法參數

                  如果指定的方法沒有參數則無需指定參數

                  注意參數出現的位置順序和實際方法定義的參數順序保持一緻

                  模式為* 表示比對所有的方法

              通過模式方法進行聲明式事務控制,同時聲明了需要復原事務的異常

              pattern【testPatternTX[1-9.]*】表示以testPatternTX開頭的所有方法

            -->

           <!--<method pattern="testPatternTX[1-9.]*">

           </method>-->

           <!--   通過模式方法進行聲明式事務控制

              pattern【testPatternTX[1-9.]*】表示以testPatternTX開頭的所有方法      

               -->  

           <method pattern="testPatternTX[1-9.]*">             

              系統級别的異常java.lang.NullPointException,導緻事務復原

           <method name="testSystemException">   

               <!--

              系統級别的異常java.lang.NullPointException将自動導緻事務復原,不管是否配置了復原異常

       </transactions>

    </manager>

</manager-config>

将manager-transaction.xml配置到主檔案manager-provider.xml中:

<managerimport file="com/chinacreator/spi/transaction/manager-transaction.xml" />

配置完畢後就可以使用業務元件了,聲明式事務将作用于業務方法。

使用帶聲明式事務的業務元件

public static void testTRANSACTION_TYPE()

       try

           AI a = (AI)BaseSPIManager.getProvider("tx.a");

           try

           {

              //事務一 REQUIRED_TRANSACTION

              a.testTXInvoke();

           }

           catch(Exception e)

              e.printStackTrace();

              //事務二 NEW_TRANSACTION 内部失敗

              a.testTXInvoke("hello.");

              //事務三 REQUIRED_TRANSACTION,

              a.testTXInvokeWithReturn();

              //事務四 MAYBE_TRANSACTION

              a.testTXInvokeWithException();

              //事務五 NO_TRANSACTION,沒有事務環境,内部執行成功則成功,否則失敗

              a.testSameName();

       catch(Exception e)

       }         

這裡簡單地舉例說明怎麼配置業務元件的事務以及簡單地通路帶事務的業務元件方法,更詳細的執行個體請通路以下位址下載下傳:

https://sourceforge.net/project/showfiles.php?group_id=238653&package_id=290546&release_id=658454

    到此通過bboss aop架構實作資料庫聲明式事務管理的功能就介紹完了,相信大家應該有一個初步的了解了,有關資料庫操作和事務管理更詳細的資訊請參考部落格中關于bboss persistent持久層架構的其他文章。