事務—EJB事務(BMT)

由於CMT依靠容器開始、提交和回滾事務,所以會限制事務的邊界位置,並且CMT不支持嵌套事務,Bean管理事務支持嵌套事務,所以需要嵌套事務時可以採用Bean管理事務。同時,BMT允許通過編程的方式來指定事務的開始、提交和回滾的位置。主要使用的是javax.transaction.UserTransaction接口。

BMT事務

如下面代碼:

Java代碼

    @Stateless)   
    @TransactionManagement(TransactionManagementType.BEAN)                                    
    public class OrderManagerBean {   
        @Resource                                                         
        private UserTransaction userTransaction;                          

        public void placeSnagItOrder(Item item, Customer customer){   
            try {   
                userTransaction.begin();                                  
                if (!bidsExisting(item)){   
                    validateCredit(customer);   
                    chargeCustomer(customer, item);   
                    removeItemFromBidding(item);   
                }   
                userTransaction.commit();                                  
            } catch (CreditValidationException cve) {                     
                userTransaction.rollback();                               
            } catch (CreditProcessingException cpe){                     
                userTransaction.rollback();                              
            } catch (DatabaseException de) {                            
                userTransaction.rollback();                          
            } catch (Exception e) {   
                e.printStackTrace();   
            }   
        }   
    }  

說明:@TransactionManagement(TransactionManagementType.BEAN) 指定了事務的類型爲BMT,上面沒有用到@TransactionAttribute,因爲它只適用於CMT,在上面代碼中,可以顯示的指定事務的開始與提交,因此更加的靈活。上面最關鍵的地方是注入了UserTransaction資源。其中獲得UserTransaction資源的方式有三種,除了用EJB資源的方式注入以外,還有以下兩種方式:

(1) JNDI查找

Java代碼

Context context = new InitialContext();   
    UserTransaction userTransaction =    
     (UserTransaction) context.lookup(“java:comp/UserTransaction”);   
    userTransaction.begin();   
    // Perform transacted tasks.   
    userTransaction.commit();   

如果在EJB之外,則可使用此方法,如在不支持依賴注入的JBoss4.2.2的Web工程或helper class即幫助器類中都可以。

(2)EJBContext

Java代碼

@Resource    
    private SessionContext context;   
    ...   
    UserTransaction userTransaction = context.getUserTransaction(); userTransaction.begin();   
    // Perform transacted tasks.   
    userTransaction.commit();   

注意:getUserTransaction方法只能在BMT中使用。如果在CMT中使用,則會拋出IllegalStateException異常。且在BMT中不能使用EJBContext的getRollbackOnly和setRollbackOnly方法,如果這樣使用,也會拋出IllegalStateException異常。

跨多個數據庫的事務控制(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
在這個節點下,添加一個子節點:

<property  name="com.arjuna.ats.jta.allowMultipleLastResources" value="true"/>

java代碼:

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

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的記錄也不會刪除
           }
   }      

“`

總結:

如果使用有狀態的Session Bean且需要跨越方法調用維護事務,那麼BMT是你唯一的選擇,當然BMT這種技術複雜,容易出錯,且不能連接已有的事務,當調用BMT方法時,總會暫停已有事務,極大的限制了組件的重用。故優先考慮CMT事務管理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章