|
精华帖 (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,但是实践下来,好像也不管用,那位用过这个的给说说? 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
最后更新时间:2007-04-06
REQUIRES_NEW这个方法应该配置到一个独立的Service中去。
|
|
| 返回顶楼 | |
|
最后更新时间: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。 |
|
| 返回顶楼 | |
|
最后更新时间: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配置文件了。类之间的调用以及拦截类的拦截都没有问题,唯一的问题就是记录日志的时候没有事务。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-04-06
楼主的问题解决了吗?
去掉异常的拦截类REQUIRES_NEW应该会起作用, 不是很理解当配置多个Spring 拦截器拦截顺序是怎么样的?关注,关键我觉得这个问题是理解Java的动态代理机制。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-04-07
jamesby 写道 楼主的问题解决了吗?
去掉异常的拦截类REQUIRES_NEW应该会起作用, 不是很理解当配置多个Spring 拦截器拦截顺序是怎么样的?关注,关键我觉得这个问题是理解Java的动态代理机制。 问题没有解决,去掉REQUIRES_NEW?我没听错?如果去掉是不行的,事务整体回滚,在调用LogService记录日志的时候,就没有事务了。但是REQUIRES_NEW不行就颇让人费解了。按照我的理解,你回滚你的事务,我重新开启一个新事务,互不影响,但是结果却不是这样,继续迷惑。。。。。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-04-07
你给你的log配一套独立的persistence不就可以了?当然log的异常处理,需要另外设置,不能一有runtimeException就回滚
|
|
| 返回顶楼 | |
|
最后更新时间: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();
}
}
}
|
|
| 返回顶楼 | |
|
最后更新时间:2007-04-07
首先去掉ExceptionHandleAdvice 是为了测试REQUIRES_NEW是否真的起作用,如果去掉起作用说明与异常拦截器有关。
如果还是不起作用说明是配置或者代码的问题。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-04-10
过了一个周末,帖子居然在前面两页找不到了,javaeye的发帖量不小啊,废话少说,继续讨论:
首先多谢楼上几位的讨论,其实我在发第一个帖子的时候已经做过类似的测试就是: 如果异常是checkedException的话,这时Exception advice拦截到,并做日志记录,那么事务会继续做提交,日志能正常记录。 后面加了一个测试:如果不抛异常的话,那么使用REQUIRES_NEW对事务没有影响,CRUD都没问题 如果那位机器方便的话,可以试试,一个很奇怪的现象。 |
|
| 返回顶楼 | |








