本文主要是在看了 关于spring声明式事务管理异常处理的测试和小结
http://www.iteye.com/topic/34867一文以后想写的,而且前段时间与jbpm整合的时候才发现自己的事务设置一直有问题,根本无法回滚(汗,都是网络上照抄的,没测试),再加上它的使用的spring版本1.2,所以觉得有必要自己再测试,加深影像。
对事务有任何不清楚的,可以参考一下这个 http://bhsc-happy.iteye.com/blog/288983
开发环境:
OS:windows XP
Web Server: jakarta-tomcat-5.0.28
DataBase Server: MS SQL Server 2000 (打了SP3补丁)
IDE: MyEclipse 6.0.1
测试案例系统结构:
web层<---->Service层<---->DAO层
web层就是Struts2,DAO使用hibernate -3.3.1.GA-dist.zip,spring是spring-framework-2.5.5
数据库表和它一样吧:
student1和Student2,表结构相同:id,name,address.其中id为主键且为自增长型.
student1表中有一条记录:
测试情形一:
web层捕获异常并处理,DAO层不捕获异常,Service也不捕获异常.
Service层接口:
public interface Student1Service {
void addStudent1(Student1 stu);
}
public interface StudentSService {
void addStudent2(Student2 stu) throws SaveException;
}
Service实现
public void addStudent1(Student1 stu) {
stufDAO.insertStuF(stu);
}
public void addStudent2(Student2 stu) throws SaveException {
String[] aa={"ww","ww","ww"};
for(int i=0;i<5;i++){ //出错
System.out.println(aa[i]);
}
stusDAO.insertStuS(stu);
}
DAO层接口
public interface StudentFDAO {
void insertStuF(Student1 stu);
}
public interface StudentSDAO {
void insertStuS(Student2 stu);
}
DAO实现
public void insertStuF(Student1 stu) {
getHibernateTemplate().save (stu);
}
public void insertStuS(Student2 stu) {
getHibernateTemplate().save (stu);
}
Action
public String execute() throws Exception{
Student1 sti=new Student1(stu1Name,stu1Address);
Student2 stu=new Student2(stu1Name,stu1Address);
try{
studentfService.addStudent1(sti);
studentsService.addStudent2(stu);
}catch(DataAccessException e){
System.out.println(“error”);
return “failer”:
}
return SUCCESS;
}
JSP
<form action="testaction.action" method="POST">
<table>
<tr><td>名:</td><td><input type="text" value="stu1Name" name="stu1Name"></td></tr>
<tr><td>地址:</td><td><input type="text" value="stu1Address" name="stu1Address"></td></tr>
<Tr><td></td><td><input type="submit" value="提交" style="width:80px"></td></Tr>
</table>
</form>
配置文件
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<!-- 定义BeanNameAutoProxyCreator-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>st1Service</value>
<value>stsService</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
运行程序:启动服务器,并部署.进入index.jsp页面,点击提交
查看数据库: 两个表中都没有新增数据。
小结:如果DAO层和Service不捕获异常而在web层捕获异常,web成功捕获异常(抛不抛出都行),spring事务管理成功!
二、Service层捕捉异常,DAO不捕捉异常(下面就简单一点了,直接给结论把)
1.如果,你在Service捕捉异常而不抛出异常,Action层捕捉不到异常,那么事物处理失败。
2.如果在Service捕捉异常并且抛出异常,那么,如果抛出的异常是Checked异常(自定义的),不会回滚。也正好验证了Spring事物里的这段话:默认情况下,事物只会出现运行异常(runtime exception)时回滚,而出现受阻异常(checked exception)时不回滚。
3.如果抛出的异常是RuntimeChecked异常(自定义的),那么事物处理成功。
所以如果你的抛出的异常是CheckException,你配置事物的时候必须加上-Exception参数,指定出现Checked异常时回滚,也就是PROPAGATION_REQUIRED,-Exception。
三、DAO捕获异常
如果DAO捕捉异常而不抛出异常,Action层捕捉不到异常,Service捕获不到异常。
运行程序:启动服务器,并部署.进入index.jsp页面,点击提交
查看数据库:student1表中新曾数据,Student2表中都没有数据。
事务处理失败。
小结:
前面的文章中提到,如果DAO的每一个方法不捕获异常,Service层捕获DataAccessException异常并抛出自己定义异常(自定义异常为DataAccessException的子类),Web层可以捕获到异常,spring事务管理成功!
然后在总结中说:
1.spring在进行声明时事务管理时,通过捕获Service层方法的DataAccessException来提交和回滚事务的,而Service层方法的DataAccessException又是来自调用DAO层方法所产生的异常.
2.我们一般在写DAO层代码时,如果继承JdbcDaoSupport 类,并使用此类所实现的JdbcTemplate来执行数据库操作,此类会自动把低层的SQLException转化成DataAccessException以及DataAccessException的子类.
3.一般在Service层我们可以自己捕获DAO方法所产成的DataAccessException,然后再抛出一个业务方法有意义的异常(ps:此异常最好继承DataAccessException),然后在Web层捕获,这样我们就可以手动编码的灵活实现通过业务方法执行的成功和失败来向用户转发不同的页面
其实这到不是因为自定义异常为DataAccessException的子类,而是DataAccessException是RuntimeException,那么它的子类也是Runtime,所以抛出异常是会回滚的。所以你的自定义异常继承自RuntimeException也可以。
再发表一些个人看发吧,在Spring中所有数据库操作异常都转换为DataAccessException这个运行时异常,不过在业务层中也有可能抛出一些其他的运行时异常,那么这时候在一些简单的项目中,我们直接用下面的方式也未尝不可:
try{
…….
………
……..(可能会有其他运行时异常,并不仅仅是DataAccessException)
}catch(Exception e){
log.error(“error”);
throw new CheckedException(“error”); //抛出受检查异常
}
然后在Action层捕捉这个受检查异常
try{
service.method();
}catch(CheckedException e){
}
这个异常,它是可以被调用者正确处理的。返回相应的提示。当然,如果抛出CheckException,那么Spring声明式事物的时候就应该加上-Exception参数,前面已经提到。
当然在一些业务逻辑比较复杂,并且要根据复杂的逻辑返回不同的试图的时候,这样整个的try{}catch(){}就不合适了,
这时候应该将不正常的事件流转换为运行时异常,并且在方法声明中详细的说明该方法可能会抛出的unChekced异常。由调用者自己去决定是否捕获unChecked异常,返回相应的视图。
总结:
1.一般DAO中不捕捉异常也不抛出异常
2.至于Service层和Action层,是在service层抛出CheckException然后由action捕捉,还是在service中全部采用unCheckException,然后在action中有选择的捕捉或者都不捕捉就要看你自己的选择了, 个人认为逻辑比较简单的可以选择前者,比较复杂就选择后者。
3.禁忌捕捉异常而不做任何处理(如果是dao层或者service层,最好抛出),不然很有可能造成事务处理失败。
分享到:
- 2008-12-08 19:56
- 浏览 2418
- 评论(1)
- 论坛回复 / 浏览 (1 / 4462)
- 查看更多
相关推荐
aop与spring事务处理
spring 事务处理
spring事务与数据库操作
Spring事务管理Demo
Spring事务流程图时序图Spring事务流程图时序图Spring事务流程图时序图Spring事务流程图时序图
Spring事务原理、Spring事务配置的五种方式
spring事务配置详解 spring事务配置详解
spring 事务spring 事务spring 事务spring 事务spring 事务
主要介绍了Spring事务处理原理步骤详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
spring事务的底层实现流程图 spring事务的底层实现流程图 spring事务的底层实现流程图 spring事务的底层实现流程图 spring事务的底层实现流程图 spring事务的底层实现流程图 spring事务的底层实现流程图 spring事务...
Spring Hibernate 事务处理 详细说明 Spring Hibernate 事务处理 详细说明
Spring中事务的传播属性详解,Spring中事务的传播属性详解
spring学习事务源码spring学习事务源码spring学习事务源码spring学习事务源码spring学习事务源码spring学习事务源码spring学习事务源码spring学习事务源码
Spring事务操作示例(四种方式),包含完整代码和数据库文件(基于MySQL,在项目sql文件夹中),可运行,学习Spring事务详见博客:http://blog.csdn.net/daijin888888/article/details/51822257
spring 事务传播 demo
这是在java里使用到spring的配置文件里,添加事务处理过程,以至于可以回滚事务,当中使用到拦截器。
spring事务源码解析
事务简介 二、程序举例环境搭建 o1. 创建数据表 ...三、使用 Spring 的事务注解管理事务 o1. 声明事务管理器 o2. 开启注解驱动 o3. 完整Spring配置文件 o4. 业务层 public 方法加入事务属性 o5. 测试
spring声明式事务处理demo。myeclipse工程
Java高级编程 实验报告 spring 声明事务 实验目的 掌握spring 声明式事务管理配置 实验环境 本实验采用本实验采用的eclipse或者 Myeclpse开发工具。Spring 4.0以上 Jdk1.7以上、oracle/mysql。