EJB事務控制(CMT和BMT兩種方式以及JTA事務)


一、EJB的事務管理分如下兩個方面:

1、CMT(容器管理事務)

2、BMT(Bean管理事務)

 

二、CMT介紹:

  容器管理事務主要是通過容器自動控制事務的開啟,提交和回滾,開發人員不需要手工編寫代碼,由容器來控制事務的邊界,一般來說是業務方法的開始

是事務的開啟,業務方法的結束是事務的提交部分,當程序遇到運行時異常,事務會自動回滾。如果遇到非運行時異常想要回滾事務的話可以用SessionCon

Text的setRollBackOnly()方法來達到目的。下面的例子是一個使用CMT的例子:(事務的控制我們一般放在Service層,而不是Dao層)

 

示例程序1:(參考publicEJB組件的NewhouseManagerImpl類)

@Stateless(name = "newhouseManager") //狀態定義實列Bean 提供遠程JNDI
@Remote(INewhouseManager.class)//定義遠程接口
@Local(INewhouseManager.class)//定義本地接口
@TransactionManagement(TransactionManagementType.CONTAINER)  // 這里來定義是CMT還是BMT

public class NewhouseManagerImpl implements INewhouseManager{       


    @EJB(beanName = "newhouseDAO") //注入dao
    private IGenericDAO<Newhouse, Integer> newhouseDAO;
      
    @TransactionAttribute(TransactionAttributeType.REQUIRED)  //這里來定義事務的傳播特性,如果調用該組件的客戶方已經開啟了事務則加入原事務,否則開啟一個新事務
    public Newhouse save(Newhouse entity) {
        LogUtil.log("saving Newhouse instance", Level.INFO, null);
        try {
            LogUtil.log("save successful", Level.INFO, null);
            entity.setBname("測試1:" + new Date());
            newhouseDAO.create(entity); //插入第一條記錄,此時事務還沒有提交,數據庫里面看不到該記錄
           
            Newhouse entity2 = new Newhouse();
            entity2.setBname("測試2");
            entity2.setPath(null); // 這里設置path為null的話,會出現運行時異常,事務會回滾,entity1和entity2將不會插入到public庫的newhouse表中
            newhouseDAO.create(entity2);
   
        } catch (RuntimeException re) {
            LogUtil.log("save failed", Level.SEVERE, re);
            re.printStackTrace();
         
        return null;
    }

PS:這里要特別注意NewhouseDAO這個類,需要添加@TransactionAttribute(TransactionAttributeType.REQUIRED)這個注解,我們項目里面原來的事務傳播屬性

設置的是REQUIRES_NEW,這樣會將原來的事務掛起,然后開啟一個新的事務。

 

三、BMT介紹

  BMT主要是通過手工編程來實現事務的開啟、提交和回滾,相對於CMT來說雖然增加了工作量,但是控制力度更細,而且更加靈活,我們可以再出現異常的時候回滾事務

,也可以通過JMS返回或者遠程調用返回值來控制事務的回滾或提交;使用BMT需要用到UserTransaction這個類的實例來實現事務的begin、commit和rollback,可以通過

Ejb注解的方式獲得這個類實例,也可以用EJBContext.getUserTransaction來獲得。下面是一個使用BMT的例子:

示例程序2:

@Stateless(name = "newhouseManager") //狀態定義實列Bean 提供遠程JNDI
@Remote(INewhouseManager.class)//定義遠程接口
@Local(INewhouseManager.class)//定義本地接口
@TransactionManagement(TransactionManagementType.BEAN) //設置為BMT事務

public class NewhouseManagerImpl implements INewhouseManager{        
    
    @Resource
    private UserTransaction ut; //注入UserTransaction
    
    @EJB(beanName = "newhouseDAO") //注入dao
    private IGenericDAO<Newhouse, Integer> newhouseDAO;
     
    @TransactionAttribute(TransactionAttributeType.REQUIRED)  //設置事務的傳播特性為required
    public Newhouse save(Newhouse entity) {
        LogUtil.log("saving Newhouse instance", Level.INFO, null);
        try {
            ut.begin();
            LogUtil.log("save successful", Level.INFO, null);
            entity.setBname("測試1:" + new Date());
            newhouseDAO.create(entity);   
            Newhouse entity2 = new Newhouse();
            entity2.setBname("測試2");
            entity2.setPath(null);
            newhouseDAO.create(entity2);
            ut.commit();            
            } catch(RuntimeException e) {

      ut.rollBack();

           }.........................

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

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

   }

 

 

測試效果和示例程序1一樣

 

 

四、跨多個數據庫的事務控制(JTA事務)

     如果想要在一個事務操作中控制多個數據庫的操作,需要如下兩步操作:

 

1、需要設置persistence.xml里面的datasouce支持jta事務,另外設置transaction-type為jta,如下所示

<persistence-unit name="public_master"  transaction-type="JTA">
         <jta-data-source>java:/public_master_db</jta-data-source>
      <properties>
             <property name="hibernate.dialect" value="com.jiwu.core.utils.BlobMySQLDialect"/>
          <property name="hibernate.hbm2ddl.auto" value="update"/>
          <property name="hibernate.show_sql" value="false" />
      </properties>
   </persistence-unit>
     
       <persistence-unit name="build_master"  transaction-type="JTA">
         <jta-data-source>java:/build_master_db</jta-data-source> 
            <property name="hibernate.dialect" value="com.jiwu.core.utils.BlobMySQLDialect"/>
          <property name="hibernate.hbm2ddl.auto" value="update"/>
          <property name="hibernate.show_sql" value="false" />
      </properties>
   </persistence-unit>

 

2、修改jboss安裝目錄下的\server\default\conf\jbossjta-properties.xml

在<properties depends="arjuna" name="jta">這個節點下,添加一個子節點<property name="com.arjuna.ats.jta.allowMultipleLastResources" value="true"/>

 

 

實例程序3:

@Stateless(name = "newhouseManager") //狀態定義實列Bean 提供遠程JNDI
@Remote(INewhouseManager.class)//定義遠程接口
@Local(INewhouseManager.class)//定義本地接口
@TransactionManagement(TransactionManagementType.BEAN) //設置為BMT事務

public class NewhouseManagerImpl implements INewhouseManager{        
    
    @Resource
    private UserTransaction ut; //注入UserTransaction
    
    @EJB(beanName = "newhouseDAO") //注入dao
    private IGenericDAO<Newhouse, Integer> newhouseDAO;
    

    
    @EJB(beanName = "buildDAO") //注入houseDAO測試
    private IGenericDAO<Build, Integer> buildDAO;  

 
    @TransactionAttribute(TransactionAttributeType.REQUIRED)  //設置事務的傳播特性為required
    public Newhouse save(Newhouse entity) {
        LogUtil.log("saving Newhouse instance", Level.INFO, null);
        try {
            ut.begin();
            LogUtil.log("save successful", Level.INFO, null);
            entity.setBname("測試1:" + new Date());
            newhouseDAO.create(entity);   
            Newhouse entity2 = new Newhouse();
            entity2.setBname("測試2");
            entity2.setPath(null); //這里不設置為null的話,不出現異常,entity1和entity2會插入到public庫的newhouse表中,另外build庫的build表中id為2的被刪除
            newhouseDAO.create(entity2);

    buildDAO.delete(2);


            ut.commit();            
            } catch(RuntimeException e) {

      ut.rollBack(); //出現異常,entity1和entity2不會插入到public庫的newhouse表中,另外build庫的build表中id為2的記錄也不會刪除

           }.........................

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

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

   }     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM