论坛首页 Java版 Spring

(郁闷系列)让我郁闷的Spring事务回滚及对其它AOP操作的影响

浏览 4498 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2007-04-16
问题很简单,使用Spring声明式事务管理,框架采用spring+hibernate,编程上采用Srping封装的Hibernate模板,架构上分为三层表示层+service+dao

首先,我采用Aop来处理Service层抛出的异常,例如MyExceptionAdvice,当然了,处理异常的类需要实现ThrowAdvice接口,但是这个时候问题就来了,假设这个时候从service层抛出Runtime异常,那么此时Spring的事务会回滚,,我MyExceptionAdvice里面规定的方法也能接收到这个异常,另外,我还想在MyExceptionAdvice里对数据库进行一步操作,那么这个时候这个操作就不会生效。最现实的例子就是,当有异常发生时,我需要向数据库插入一条日志。但是基于上述我所说的,这条日志不能成功的插入到数据库。

原因分析及尝试的解决办法:

原因应该是,由于抛出runtime异常,所以事务回滚造成的,这时,我们就会想,能不能重新启动一个事务,按照Spring事务定义的策略,可以在事务定义的时候将写日志的方法定义为REQUIRES_NEW,但是实践下来,好像也不管用,那位用过这个的给说说?
   
最后更新时间:2007-04-06
REQUIRES_NEW这个方法应该配置到一个独立的Service中去。
   
0 请登录后投票
最后更新时间:2007-04-06
lizwjiang 写道
问题很简单,使用Spring声明式事务管理,框架采用spring+hibernate,编程上采用Srping封装的Hibernate模板,架构上分为三层表示层+service+dao

首先,我采用Aop来处理Service层抛出的异常,例如MyExceptionAdvice,当然了,处理异常的类需要实现ThrowAdvice接口,但是这个时候问题就来了,假设这个时候从service层抛出Runtime异常,那么此时Spring的事务会回滚,,我MyExceptionAdvice里面规定的方法也能接收到这个异常,另外,我还想在MyExceptionAdvice里对数据库进行一步操作,那么这个时候这个操作就不会生效。最现实的例子就是,当有异常发生时,我需要向数据库插入一条日志。但是基于上述我所说的,这条日志不能成功的插入到数据库。

原因分析及尝试的解决办法:

原因应该是,由于抛出runtime异常,所以事务回滚造成的,这时,我们就会想,能不能重新启动一个事务,按照Spring事务定义的策略,可以在事务定义的时候将写日志的方法定义为REQUIRES_NEW,但是实践下来,好像也不管用,那位用过这个的给说说?


REQUIRES_NEW所对应的函数的对象,是从spring中ioc来的?还是直接调用了同一个对象中的另一个方法?
如果直接调用了这个方法,那么只是普通的java函数调用,绕过了spring。
   
0 请登录后投票
最后更新时间:2007-04-06
ok,都怪俺没有说清楚,用例子来说一下,

业务Service的例子:

public class ExampleServiceImpl implements ExampleService{
    public void saveExample(.....){
       ..........
    }
} 


记录日志的Service:
public class LogServiceImpl implements LogService{
   public void writeLog(){
       .......
   }
}


异常的拦截类:

public class ExceptionHandleAdvice implements ThrowsAdvice{
    LogService logThrowService = null;

    public void afterThrowing(Method method,Object[] args,Object target,Exception e) throws Throwable {
       logThrowService.writeLog();
    }

    public void setLogThrowService(LogService logThrowService) {
		this.logThrowService = logThrowService;
	}
}


Spring配置:
<tx:advice id="txAdvice" transaction-manager="myTxManager">
		<tx:attributes>
			<tx:method name="save*"/>
			<tx:method name="update*"/>
			<tx:method name="delete*"/>
			<tx:method name="writeLog*" propagation="REQUIRES_NEW"/>
			<tx:method name="find*" read-only="true"/>
		</tx:attributes>
	</tx:advice>


注意上面的ExampleService,LogService及他们的实现,以及处理异常的拦截类都配置到Spring配置文件了。类之间的调用以及拦截类的拦截都没有问题,唯一的问题就是记录日志的时候没有事务。
   
0 请登录后投票
最后更新时间:2007-04-06
楼主的问题解决了吗?
去掉异常的拦截类REQUIRES_NEW应该会起作用,
不是很理解当配置多个Spring 拦截器拦截顺序是怎么样的?关注,关键我觉得这个问题是理解Java的动态代理机制。
   
0 请登录后投票
最后更新时间:2007-04-07
jamesby 写道
楼主的问题解决了吗?
去掉异常的拦截类REQUIRES_NEW应该会起作用,
不是很理解当配置多个Spring 拦截器拦截顺序是怎么样的?关注,关键我觉得这个问题是理解Java的动态代理机制。


问题没有解决,去掉REQUIRES_NEW?我没听错?如果去掉是不行的,事务整体回滚,在调用LogService记录日志的时候,就没有事务了。但是REQUIRES_NEW不行就颇让人费解了。按照我的理解,你回滚你的事务,我重新开启一个新事务,互不影响,但是结果却不是这样,继续迷惑。。。。。
   
0 请登录后投票
最后更新时间:2007-04-07
你给你的log配一套独立的persistence不就可以了?当然log的异常处理,需要另外设置,不能一有runtimeException就回滚
   
0 请登录后投票
最后更新时间:2007-04-07
我说的是先把你的ExceptionHandleAdvice 先去掉,也就是先不配置异常拦截器,看可不可以。

REQUIRES_NEW当然不能去掉拉:

代码应该类似如下:

public class ExampleServiceImpl implements ExampleService{   
    public void saveExample(.....){ 
        try
        {
            dao.save();
        }catch(Exception e) //or RuntimeException
        {
            writeLog();
            throw new RuntimeException();
        }
    }   
}   

public class LogServiceImpl implements LogService{   
   public void writeLog(){   
        try
        {
            logDao.log();
        }catch(Exception e)
        {
            loggger.log("log exception ",e);
            throw new RuntimeException();
        }
   }   
}  
   
0 请登录后投票
最后更新时间:2007-04-07
首先去掉ExceptionHandleAdvice 是为了测试REQUIRES_NEW是否真的起作用,如果去掉起作用说明与异常拦截器有关。

如果还是不起作用说明是配置或者代码的问题。
   
0 请登录后投票
最后更新时间:2007-04-10
过了一个周末,帖子居然在前面两页找不到了,javaeye的发帖量不小啊,废话少说,继续讨论:
首先多谢楼上几位的讨论,其实我在发第一个帖子的时候已经做过类似的测试就是:
如果异常是checkedException的话,这时Exception advice拦截到,并做日志记录,那么事务会继续做提交,日志能正常记录。

后面加了一个测试:如果不抛异常的话,那么使用REQUIRES_NEW对事务没有影响,CRUD都没问题

如果那位机器方便的话,可以试试,一个很奇怪的现象。
   
0 请登录后投票
论坛首页 Java版 Spring

跳转论坛:
JavaEye推荐