Spring声明式事务异常回滚机制
2015-12-27 10:33
453 查看
本文主要描述Spring的声明式事务的回滚机制。
首先看一个Service层的方法,该方法调用两个DAO层的方法分别往数据库中的两张表中插入数据,实现一个业务逻辑。而且根据业务规则,这两个插入动作是要进行事务控制的原子操作,即要么一起成功,要么一起失败,否则会导致数据一致性问题。
若在这个Service层的方法上不加任何事物注解,则事物的边界为DAO层的方法。即当程序执行完第一个DAO方法的调用后,事物已经被提交了。(可以通过pl/sql developer工具连接到数据库后,发现此时记录已经被插入到表中了来验证)。因此,第二句的DAO层的方法如果一旦执行错误,已经无法将上一句DAO层方法以及插入到数据库中的数据进行回滚,导致数据一致性问题。
Spring通过@Transaction注解实现声明式事物。一般事物的边界定义在Service层的方法中。
若如上述代码一样,只加了一个默认的@Transactional标注,而不加任何标注参数。则此时,当第一个DAO层方法执行完成后,事务没有被提交(可以通过pl/sql developer工具连接到数据库后,发现此时记录没有被插入到表中来验证)。当程序执完整个Service方法,且上述两句DAO层方法都执行成功,则事务才被提交(可以通过pl/sql developer工具连接到数据库后,发现此时两条记录都已经被插入到表中来验证)
若第二句DAO层方法执行失败,Spring会根据异常类型来做不同的处理,即:若执行失败,若抛出的异常为RuntimeExcepition类型或其子型的异常对象,则上句DAO层语句执行的结果会被回滚。否则,上句执行的结果会被提交。这样也会导致业务原子信被破坏,导致数据不一致的情况。
为了保证在Service层的方法中,无论遇到任何类型的异常,都让事务进行回滚,而不是让之前已经执行成功的语句提交,则必须在@Transactional注解中增加如下参数rollbackFor:
由于Exception是所有异常类的超类,这样对于任何异常,Spring都会进行回滚,而不会将引发异常之前已经执行成功的提交掉。
对于那些我们在代码中主动抛出的异常,我们可以将rollbackFor参数指定为这些特定异常,即遇到该异常,就进行回滚操作。
上述Service方法作为一个原子业务逻辑,实现了两个操作,一个是调用DAO层方法往数据库里面插入数据,另一个是调用另一个系统的Webservice接口,将数据推送过去。若第一个DAO层方法执行成功,而第二个操作由于网络等原因导致调用Webservice接口失败,则程序会主动抛出ArcpipeException异常,而由于事务注解中已经设置了参数rollbackFor=ArcpipeException.class,因此该事务会被回滚掉。
首先看一个Service层的方法,该方法调用两个DAO层的方法分别往数据库中的两张表中插入数据,实现一个业务逻辑。而且根据业务规则,这两个插入动作是要进行事务控制的原子操作,即要么一起成功,要么一起失败,否则会导致数据一致性问题。
@Override public void SaveDispatchInfoService(GxluProjectInfo projInfo, GxluDispatchResultSchedule dispatchResultSchedule) throws Exception { *projectInfoDAO.updateOrderInfoByOrderId(projInfo);* //此句执行完后,事务已经被提交了。 gxluDispatchResultScheduleDAO.saveInstance(dispatchResultSchedule);//若此句执行发生异常,已无法将上一句执行的结果进行回滚,产生数据一致性问题。 }
若在这个Service层的方法上不加任何事物注解,则事物的边界为DAO层的方法。即当程序执行完第一个DAO方法的调用后,事物已经被提交了。(可以通过pl/sql developer工具连接到数据库后,发现此时记录已经被插入到表中了来验证)。因此,第二句的DAO层的方法如果一旦执行错误,已经无法将上一句DAO层方法以及插入到数据库中的数据进行回滚,导致数据一致性问题。
Spring通过@Transaction注解实现声明式事物。一般事物的边界定义在Service层的方法中。
@Override @Transactional public void SaveDispatchInfoService(GxluProjectInfo projInfo, GxluDispatchResultSchedule dispatchResultSchedule) throws Exception { projectInfoDAO.updateOrderInfoByOrderId(projInfo);//此句执行完后,事务没有被提交。 gxluDispatchResultScheduleDAO.saveInstance(dispatchResultSchedule) 4000 ;//此句若执行失败,若抛出的异常为RuntimeExcepition类型或其子型的异常对象,则上句DAO层语句执行的结果会被回滚。否则,上句执行的结果会被提交。这样也会导致业务原子信被破坏,导致数据不一致的情况。 }//当程序执完整个Service方法,且上述两句都执行成功,则事务才被提交
若如上述代码一样,只加了一个默认的@Transactional标注,而不加任何标注参数。则此时,当第一个DAO层方法执行完成后,事务没有被提交(可以通过pl/sql developer工具连接到数据库后,发现此时记录没有被插入到表中来验证)。当程序执完整个Service方法,且上述两句DAO层方法都执行成功,则事务才被提交(可以通过pl/sql developer工具连接到数据库后,发现此时两条记录都已经被插入到表中来验证)
若第二句DAO层方法执行失败,Spring会根据异常类型来做不同的处理,即:若执行失败,若抛出的异常为RuntimeExcepition类型或其子型的异常对象,则上句DAO层语句执行的结果会被回滚。否则,上句执行的结果会被提交。这样也会导致业务原子信被破坏,导致数据不一致的情况。
为了保证在Service层的方法中,无论遇到任何类型的异常,都让事务进行回滚,而不是让之前已经执行成功的语句提交,则必须在@Transactional注解中增加如下参数rollbackFor:
@Override @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class) public void SaveDispatchInfoService(GxluProjectInfo projInfo, GxluDispatchResultSchedule dispatchResultSchedule) throws Exception { projectInfoDAO.updateOrderInfoByOrderId(projInfo); gxluDispatchResultScheduleDAO.saveInstance(dispatchResultSchedule); }
由于Exception是所有异常类的超类,这样对于任何异常,Spring都会进行回滚,而不会将引发异常之前已经执行成功的提交掉。
对于那些我们在代码中主动抛出的异常,我们可以将rollbackFor参数指定为这些特定异常,即遇到该异常,就进行回滚操作。
@Override @Transactional(propagation=Propagation.REQUIRED, rollbackFor=ArcpipeException.class) public void insertRouteConditions(List<GxluProjectInfo> projInfos) throws ArcpipeException,JAXBException,RemoteException,Exception { //插入路由选择条件(起始、终止)到数据库 for (GxluProjectInfo projInfo : projInfos) { projectInfoDAO.insertRouteCondition(projInfo); } //将选择条件推送给综资Webservice Body bodyOut=convertBean2dto(projInfos); String configConditionXml = JaxbUtil.convertToXml(bodyOut); String configConditionResultXml=configConditionItfService.submitConfigCondition2Purdo(configConditionXml); Body bodyIn = JaxbUtil.converyToJavaBean(configConditionResultXml, Body.class); if(!"1".equals(bodyIn.getConfigConditionResultInfo().getErrorCode())) { throw new ArcpipeException(); //若抛出该异常,则整个事务将被回滚 } }
上述Service方法作为一个原子业务逻辑,实现了两个操作,一个是调用DAO层方法往数据库里面插入数据,另一个是调用另一个系统的Webservice接口,将数据推送过去。若第一个DAO层方法执行成功,而第二个操作由于网络等原因导致调用Webservice接口失败,则程序会主动抛出ArcpipeException异常,而由于事务注解中已经设置了参数rollbackFor=ArcpipeException.class,因此该事务会被回滚掉。
相关文章推荐
- 一个jar包里的网站
- 一个jar包里的网站之文件上传
- 一个jar包里的网站之返回对媒体类型
- Ruby中的异常处理代码编写示例
- SQL Server误区30日谈 第1天 正在运行的事务在服务器故障转移后继续执行
- 浅析SQL Server中包含事务的存储过程
- Mysql中的事务是什么如何使用
- MySql的事务使用与示例详解
- C#分布式事务的超时处理实例分析
- C#中的事务用法实例分析
- MySQL抛出Incorrect string value异常分析
- SQL Server的事务操作隔离模式介绍
- MySQL中事务概念的简洁学习教程
- C#处理Access中事务的方法
- oracle 合并查询 事务 sql函数小知识学习
- 详解JavaScript中的异常处理方法
- 模拟Spring的简单实现
- java程序中的延时加载异常及解决方案
- 解析Java异常的栈轨迹及其相关方法
- spring+html5实现安全传输随机数字密码键盘