您的位置:首页 > 编程语言 > Java开发

Spring声明式事务异常回滚机制

2015-12-27 10:33 453 查看
本文主要描述Spring的声明式事务的回滚机制。

首先看一个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,因此该事务会被回滚掉。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring 事务 异常