请教关于Spring事务的问题

liuex 发布于 2012/02/24 16:22
阅读 628
收藏 0

我们代码中使用Hibernate做ORM,使用Spring切面控制业务逻辑层的事务,代码如下:具体业务逻辑实现类XXXXServiceImpl上使用@Service标注为服务,使用 @Transactional标注为使用Spring的事务控制,参数 rollbackFor = ApplicationException.class指定了当发生ApplicationException时回滚整个方法的事务。其中ApplicationException是业务异常,任何业务操作失败时都会抛出这个异常,通知调用方业务执行失败了。

现在遇到一个问题,就是我在方法中记录数据库日志的时候,如果业务逻辑方法执行异常了,那么连finally块中记录数据库日志的代码也会被回滚掉,这显然不符合日志的要求。。。

请教一下,需要咋样才能保证不论业务执行成功还是失败,都能正常的记录数据库日志捏?

@org.springframework.stereotype.Service
@Transactional(rollbackFor = ApplicationException.class)
public class SubscriptionServiceImpl extends CommonServiceImpl implements SubscriptionServiceRemote, SubscriptionService4SOAP {

      public BatchSubscriptionResult batchSubscription(Long userId, Long productId) throws ApplicationException {
          try {
              //1、处理业务逻辑
          } finally {
              //2、记录数据库日志,包括执行结果、参数等
          }
      }
}

加载中
0
邸星星
邸星星
jms 单独处理日志
0
乱世键客
乱世键客
汗,在1处抛出异常会导致2处的代码“回滚”?没道理啊。
liuex
liuex
实际情况就是这样的。。。 实际上从Spring获取到的任何Service对象都是Spring动态生成的XXXProxy实例,我们调用上面的业务方法都是通过Spring中转的。 所以Spring已发现方法异常了,就会根据XXServiceImpl类上面的@Transactional标注进行相应的回滚,1、2在同一个方法中,所以会一起被回滚掉的。
0
liuex
liuex

引用来自“邸星星”的答案

jms 单独处理日志

一个维护了5~7年的项目了,整个系统规模比较大,以前的所有数据库日志要么是spring切面日志,要么就是直接调用dao创建日志,到了现阶段不可能只是为了实现一个功能点就增加一种新的日志方式啊。。。

不过JMS异步日志模型倒是一个好思路啊,可以在新项目中借鉴呢。

ps:以前在OSS中用过JMS异步接收工单和回单,我记得当时OSS负载很大,JMS老出问题。。。如果用在日志系统中,会不会由于JMS模块崩溃导致整个系统卡住呢。。。我们系统的log4j文件日志相当恐怖,每天好几G。

0
邸星星
邸星星

jms 处理比较耗时的记录数据库日志。 应该不会很多吧。


liuex
liuex
恩,不错的思路~
0
hunterli
hunterli
finally块中取数据库连接时,不从spring上下文中取,这样spring就管不着了吧。
0
liuex
liuex

引用来自“hunterli”的答案

finally块中取数据库连接时,不从spring上下文中取,这样spring就管不着了吧。

目前大部分数据库操作都是通过Hibernate完成的,在XxxServiceImpl这样的业务实现类中,我个人意见认为根本就不应该再使用任何JDBC这种底层的工具,操作的视角是更高层的抽象,比如“发起订购”,“激活用户”,“用户确认付款”这样的一个业务动作,而不再是“更新XX表的某个字段”,否则还要业务逻辑对象干嘛,直接全部DAO算了。。。

我刚才想了下既然Spring回滚的是整个方法,我把记录数据库日志拆分到另外一个方法中新开一个事务,这样业务操作失败的时候应该就不会把日志给回滚掉了。我觉得应该可行的,还没验证呢。

liuex
liuex
@hunterli : 我觉得应该会比JDBC的慢一些的,现在程序写出来了,还没测试。。。
hunterli
hunterli
给日志操作单独开事务,不知会不会影响性能。
0
卧枝会中田
卧枝会中田

引用来自“liuex”的答案

引用来自“hunterli”的答案

finally块中取数据库连接时,不从spring上下文中取,这样spring就管不着了吧。

目前大部分数据库操作都是通过Hibernate完成的,在XxxServiceImpl这样的业务实现类中,我个人意见认为根本就不应该再使用任何JDBC这种底层的工具,操作的视角是更高层的抽象,比如“发起订购”,“激活用户”,“用户确认付款”这样的一个业务动作,而不再是“更新XX表的某个字段”,否则还要业务逻辑对象干嘛,直接全部DAO算了。。。

我刚才想了下既然Spring回滚的是整个方法,我把记录数据库日志拆分到另外一个方法中新开一个事务,这样业务操作失败的时候应该就不会把日志给回滚掉了。我觉得应该可行的,还没验证呢。

我刚才想了下既然Spring回滚的是整个方法,我把记录数据库日志拆分到另外一个方法中新开一个事务,这样业务操作失败的时候应该就不会把日志给回滚掉了。我觉得应该可行的,还没验证呢

这个应该可行,新开个方法记录日志,finally代码块中执行

@Transactional(readOnly = false, propagation = Propagation.PROPAGATION_REQUIRES_NEW  

新方法的事务传遍属性改成PROPAGATION_REQUIRES_NEW即可表示 新建事务,如果当前存在事务,把当前事务挂起。 

返回顶部
顶部