EJB3 事务控制
一、EJB的事务管理分如下两个方面:
1、CMT(容器管理事务)
2、BMT(Bean管理事务)
二、CMT介绍:
容器管理事务主要是通过容器自动控制事务的开启,提交和回滚,开发人员不需要手工编写代码,由容器来控制事务的边界,一般来说是业务方法的开始
是事务的开启,业务方法的结束是事务的提交部分,当程序遇到运行时异常,事务会自动回滚。
如果遇到的是非运行时异常想要回滚事务的话可以用SessionConText的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这个类的create方法抛出的是非运行时异常时,这里假设插入第一条记录时时成功的,插入第二天记录时抛出了非运行时异常,那么ejb的事物是不会回滚的,当遇到这种情况时,需要像以下操作(也就是用SessionContext的setRollbackOnly()方法进行事物回滚):
示例程序2:
@Stateless(name = "newhouseManager") //状态定义实列Bean 提供远程JNDI
@Remote(INewhouseManager.class)//定义远程接口
@Local(INewhouseManager.class)//定义本地接口
@TransactionManagement(TransactionManagementType.CONTAINER) // 这里来定义是CMT还是BMT
public class NewhouseManagerImpl implements INewhouseManager{
@Resource
private SessionContext context;
@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 (Exception re) {
context.setRollbackOnly();
LogUtil.log("save failed", Level.SEVERE, re);
re.printStackTrace();
return null;
}
}
}
三、BMT介绍
BMT主要是通过手工编程来实现事务的开启、提交和回滚,相对于CMT来说虽然增加了工作量,但是控制力度更细,而且更加灵活,我们可以再出现异常的时候回滚事务,也可以通过JMS返回或者远程调用返回值来控制事务的回滚或提交;使用BMT需要用到UserTransaction这个类的实例来实现事务的begin、commit和rollback,可以通过Ejb注解的方式获得这个类实例,也可以用EJBContext.getUserTransaction来获得。下面是一个使用BMT的例子:
示例程序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;
@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();
}
}
}
四、跨多个数据库的事务控制(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>
2、修改jboss安装目录下的\server\default\conf\jbossjta-properties.xml
在<properties depends="arjuna" name="jta">这个节点下,添加一个子节点<property name="com.arjuna.ats.jta.allowMultipleLastResources" value="true"/>
转载于:https://my.oschina.net/mn1127/blog/512860
上一篇: Hessian的使用
推荐阅读