关于Spring AOP的事务处理

更新时间:2023-12-23 07:04:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

关于外汇局项目使用Spring AOP进行事务控制的总结

---软件开发事业部 黄立坤

? 事务控制

事务是一个最小的工作单元,不论成功与否都作为一个整体进行工作。

由于事务是由几个任务组成的,因此如果一个事务作为一个整体是成功的,则事务中的每个任务都必须成功。如果事务中有一部分失败,则整体事务失败。不会有部分完成的事务。

我们在项目开发过程中,对于一个业务操作可以定义为一个事务。

如外汇局项目中登记表登记业务,当用户填写完毕表单项,点击登记时进入业务方法。该方法中不但涉及到保存操作,还涉及更新金额,记录日志等多个数据库操作。如图:

用户触发事件开发可以是原子数据库操作,也可以是多个原子数据库操作的集合业务操作事件结束

当情况为一个原子数据库操作的时候,业务方法中抛出异常,该原子数据库操作在数据库层会自动回滚。

当情况为多个原子数据库操作作为一个集合对应用户一次操作业务时,就需要将这个数据库操作集合作为一个事务进行控制,如上文所说,一个操作出现异常导致失败,整个事务失败,所有数据库操作回滚。若不进行这样控制,后果可以想象,尤其对于金融项目。例如,银行转账的例子,如果从一个帐户中提出钱,而在钱到达另一个帐户前出错,若不将整个转账作为一个事务进行处理话,钱会莫名其妙地消失。

? Spring AOP概述

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程(也叫面向方面),可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。

在了解Spring AOP之前,我们需要先了解AOP的概念。如上所说,AOP是面向切面编程的思想。举个形象点的例子:做饭,在你的业务方法中也许只有如何去做这个饭。但是现在有这样一个需求,做饭之前需要先开燃气,做饭之后要关燃气。将做饭过程当做一根黄瓜,就需要在黄瓜头剁一刀,在那个剖面加入开燃气,在黄瓜尾剁一刀,在这个剖面加入关燃气。

添加打开燃气做饭业务流程添加关闭燃气

了解了AOP,我们来看看Spring中如何实现AOP编程的。

Spring AOP思想的实现是通过动态代理机制实现的。将横切业务逻辑设计成一个类,作为处理者(Handler)服务于各个核心业务类。业务方法实现一个接口,在处理者(Handler)的方法中可以生成该接口的一个代理业务实现类来反射业务方法。如上面的例子,我们可以将燃气操作设计成一个类,他作为一个处理者。在这个处理者的方法中我们可以反射到你实现接口的实现类业务方法,从而服务于你做饭,服务你做任何饭。

我们可以把AOP当做是Spring的一种增强,它可以使我们自定义切面,自定义获取切面后的操作。

? Spring AOP 实现事务控制

了解了以上的内容,对于Spring AOP实现事务控制,只需要将我们上面提到的例子中的天然气操作换成开启事务、关闭事务即可。但是具体到编码中,可以有以下问题:

1. 如何获取切面。

2. 如何添加事务和反射业务方法。

对于第一个问题,Spring已经提供给了我们。Spring支持切入点表达式的匹配模式。如外汇局项目Spring配置文件中下如下:

.*Service\\.execute.* .*Service\\.save.* .*Service\\.remove.* .*Service\\.add.* .*Service\\.modify.* .*Service\\.send.* .*Service\\.load.* .*Service\\.hand.* .*Service\\.adjust.*

黄色标注部分即为表达式匹配模式,对于每一次的后台请求。过滤器会去比较请求

Service方法的前几个字母,如果以add、save等开头的话,就会在后面注入的绿色标注bean com.neusoft.safetrade.common.aop.TransactionInterceptor中拦截到。如外汇局项目登记表登记操作,当用户点击保存按钮,前台JS会给后台发送异步请求,

unieap.Action.request({

url:\ sync:false, load:function(dcS){ ……

}

发送url为registTableService.saveRegistTable,匹配配置中的.*Service\\.save.*,于是,在进入本身的业务方法前会先进入到拦截器的方法中。

对于第二个问题,可以看如下代码

public Object invoke(MethodInvocation methodInvocation) throws Throwable { log.debug(\事务拦截器处理开始.....\ Object r = null; UDOLinkTransaction tx = DrmDaoSupport.getTransaction(); try { tx.beginTran();//事务开启 r = methodInvocation.proceed();//业务方法 tx.commitTran();//事务提交 log.debug(\事务提交.\ } catch (Throwable t) { log.error(\事务处理异常:事务拦截器中处理异常!\ tx.rollbackTran();//抛出异常,事务回滚 log.debug(\事务回滚.\ t.printStackTrace(); if (t instanceof SafeException) { throw t; } throw new SystemRuntimeException(900005, \业务操作失败\ } return r; }

此方法写在com.neusoft.safetrade.common.aop.TransactionInterceptor中,该类实现MethodInterceptor接口的invoke方法,该方法通过methodInvocation.proceed()反射调用业务方法的执行,在业务方法的前后分别加上了业务的开启与关闭。从而达到事务控制的要求。还以登记表登记用户点击保存为例,

public interface IRegistTableService {

public IDataCenter saveRegistTable(IDataCenter dc); …… }

methodInvocation.proceed()其实执行就是saveRegistTable方法,在执行saveRegistTable之前添加了tx.beginTran()事务开启,若没有异常,saveRegistTable方法执行完毕后添加了tx.commitTran()事务提交。若有异常抛出,则添加了tx.rollbackTran();事务回滚。

使用Spring AOP进行事务控制需要具备一定的规则,类似外汇局项目,若是开发人员的业务Service或者说业务Service中的业务方法命名不按照事前定义好的规则进行命名的话,AOP是拦截不到的。也就是说事务控制是无法加载的。以登记表登记为例,当业务Service实现类的接口命名为IRegistTableService可以拦截到,但是若命名为IregistTableApplication,事务是无法加载的。接口中方法命名saveRegistTable可以拦截到加载事务,但是若是doSaveRegistTable则拦截不到,事务也无法控制。

还有一个需要注意的一点就是,AOP方式必须要实现接口,所有的命名规则都是对应的接口而言,如接口的命名,接口中方法的命名。

本文来源:https://www.bwwdw.com/article/rug5.html

Top