Spring事务管理例子
关于spring事务管理以及异常处理的帖子,本论坛争论颇多,各有各的测试代码,也各有各的测试结果,不知道是spring版本的不同还是各测试的例子的不同而导致测试结果出现差异.本人也很想弄清楚spring是如何对Service进行事务管理的,并且还去看了一下spring框架关于事务管理几个相关类的源码,可惜由于本人功力有限,只看懂了皮毛.既然源代码看不懂,那么只有运用例子进行测试,虽然笨了点,不过管是白猫还是黑猫,能捉老鼠就是好猫.:)为引起不必要的争论,本帖子只针对本案例的测试结果进行小结,并保证此测试代码在本人的运行环境绝对正确.
开发环境:
OS:windows 2003 Server
Web Server: jakarta-tomcat-5.0.28
DataBase Server: MS SQL Server 2000
IDE: Eclipse 3.2.0
测试案例系统结构:
web层<---->Service层<---->DAO层
web层使用struts 1.1,DAO使用的spring的JDBC,spring版本1.2
数据库中有两张表:
student1和Student2,表结构相同:id,name,address.其中id为主键且为自增长型.
student1表中有一条记录:
sturts-config.xml
applicationContext.xml
运行程序:启动服务器,并部署.进入index.jsp页面,点击"执行"超链接"---->页面跳向shibai.jsp
查看控制台:打印有:action execute service exception!
查看数据库: student1表中的[1 xiaoming wuhan] 记录仍然存在,student2表仍然为空.
小结:如果DAO层和Service不捕获异常而在web层捕获异常,web成功捕获异常,spring事务管理成功!
测试情形二:
web层捕获异常并处理,Service捕获异常并处理,DAO层不捕获异常.
修改StudentManagerServiceImp类public class StudentManagerAction extends Action{ public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { try{ WebApplicationContext appContext=WebApplicationContextUtils. getWebApplicationContext(this.getServlet().getServletContext()); StudentManagerService stdm=(StudentManagerService)appContext. getBean("stdServiceManager"); stdm.bus_method(); return mapping.findForward("chenggong"); } catch(StudentManagerException e){ System.err.println("action execute service exception!"); return mapping.findForward("shibai"); } } }
运行程序:启动服务器,并部署.进入index.jsp页面,点击"执行"超链接"---->页面跳向shibai.jsp
查看控制台:打印有:service execute exception! action execute service exception!
查看数据库:student1表中的 [1,xiaoming,wuhan] 记录仍然存在,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层捕获,这样我们就可以手动编码的灵活实现通过业务方法执行的成功和失败来向用户转发不同的页面. ?