事务—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事务管理。

你可能感兴趣的:(java,ejb,事务)