1、由于采用的是SpringMVC、MyBatis,故统一采用了注释来声明Service、Controller。由于服务器启动时的加载配置文件的顺序为web.xml---root-context.xml(Spring的配置文件)---servlet-context.xml(SpringMVC的配置文件),如果Controller在root-context.xml(Spring的配置文件)文件中扫描则Controller会先进行扫描装配,但是此时service还没有进行事务增强处理,得到的将是原样的Service(没有经过事务加强处理,故而没有事务处理能力),所以我们必须在root-context.xml(Spring的配置文件)中不扫描Controller,将Controller放在servlet-context.xml(SpringMVC的配置文件)中扫描。
事务的配置一般会在root-context.xml(Spring的配置文件)中配置或者Spring-Mybatis.xml中配置;Controller会放在servlet-context.xml(SpringMVC的配置文件)中扫描,如果Controller不放在servlet-context.xml(SpringMVC的配置文件)中扫描请求接口会报404;Service和Dao会放在root-context.xml(Spring的配置文件)中扫描。
2、如果你用了mysql数据库,需要(show engines;)查看数据库存储引擎是不是InnoDB,因为MyISAM是不支持事物的,如果不是需要改成InnoDB。
3、Spring AOP异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样AOP代理才能捕获到方法的异常,才能进行回滚,默认情况下AOP只捕获runtimeexception的异常,但可以通过配置来捕获特定的异常并回滚,换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion(),这样程序异常时才能被AOP捕获进而回滚。
解决方案:
方案1.例如service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw new RuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异常并处理。
方案2.在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常。
在service类前加上@Transactional,声明这个service所有方法需要事务管理。每一个业务方法开始时都会打开一个事务。Spring默认情况下会对运行期例外(RunTimeException)进行事务回滚。这个例外是unchecked;如果遇到checked意外就不回滚。
如何改变默认规则:
1)让checked例外也回滚:在整个方法前加上 @Transactional(rollbackFor=Exception.class)
2)让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
3)不需要事务管理的(只查询的)方法:@Transactional(propagation=Propagation.NOT_SUPPORTED)
注意: 如果异常被try{}catch{}了,事务就不回滚了,如果想让事务回滚必须再往外抛try{}catch{throw Exception}。
附:execution表达式
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.loongshawn.method.ces..*.*(..))" />
<aop:aspect ref="logAspect">
<aop:before pointcut-ref="pointcut" method="beforeAdvice"/>
<aop:after-returning pointcut-ref="pointcut" arg-names="joinPoint,retValue" returning="retValue" method="afterAdvice"/>
</aop:aspect>
</aop:config>
上述配置为AOP配置代码片段,其中expression部分为定义切点的表达式部分,如下:
execution(* com.loongshawn.method.ces..*.*(..))
注意:markdown中符号“*”是加粗,因此输出“*”符号需要进行转义“*”。
表达式结构解释如下:
标识符 | 含义 |
---|---|
execution() | 表达式的主体 |
第一个“*”符号 | 表示返回值的类型任意 |
com.loongshawn.method.ces | AOP所切的服务的包名,即,需要进行横切的业务类 |
包名后面的“..” | 表示当前包及子包 |
第二个“*” | 表示类名,*即所有类 |
.*(..) | 表示任何方法名,括号表示参数,两个点表示任何参数类型 |