在使用Spring的事务注解@Transactional的时候遇到几个坑

    今天在用@Transactional的时候遇到几个很奇怪的问题,一段从旧程序上拷过来的代码结果死活不执行,让我百思不得其解。

    旧的代码是这样的,一直运行正常

    @Override
    public Pager getPager(Map<String, Object> paramMap) {
        List<TaSjjhLog> logList = TaSjjhLog.getWaitingList();
        if(logList != null && logList.size() > 0){
            this.saveList(logList);
        }
        return this.dao.getPager(paramMap);
    }

    @Transactional
    private void saveList(List<TaSjjhLog> logList) {
        for (TaSjjhLog log : logList) {
            log.setErrorMessage(this.handleErrorMsg(log.getErrorMessage()));
            this.dao.save(log);
        }
        TaSjjhLog.removeAllFromWaitingList(logList);
    }
    新的代码是这样的,结果保存操作不起作用
    @Override
    public List<ChangeLog> getList(Pager<ChangeLog> pager, String mc) {
        List<changelog> logList = ChangeLog.getWaitingList();
        if(logList != null && logList.size() > 0){
            this.service.saveList(logList);
        }
        return this.dao.getList(pager, mc);
    }

    @Transactional
    private void saveList(List<ChangeLog> logList) {
        logList.stream().forEach(log->{
            log.setErrorMessage(this.handleErrorMsg(log.getErrorMessage(), log.getRecordCount(), log.getExecutedCount()));
            this.dao.save(log);
            ChangeLog.removeFromWaitingList(log);
        });
    }</changelog>

起初我还以为是Lambda表达式的问题,改写了一下,结果是一样的。

然后我就不停的测试,不停的改@transactional的事务级别,结果都没用。

然后我就看我的dao里面的基类,结果发现了一点不同

旧代码在dao的基类上加了@Transactional,而新代码则是加了@Transactional(readOnly=true)

所以dao里面的save方法,旧代码是有事务的,而新代码则是只读的事务。可以问题来了,为什么我在新代码的saveList上加的事务注解不起作用?

我在网上没有找到相应的解释,但是通过我的测试和对spring的认识,我觉得spring的事务是通过切面(或者也可以说是代理)实现的,当你调用一个代理类的接口,如果其标注了事务注解,则会生效,

而我这个saveList是在service里面自己的方法调用的,这个注解不会被处理。

于是我修改代码,结果使用了三种方案全部失败:

1. 在getList上加事务注解,取消saveList上的注解:这种方式可以保存数据成功,但是查询出来的数据在SpringMVC转换结果为json的时候报错,说no session.

2. 在dao基类的save方法上加注解:结果同上

3. service提供两个接口给controller,分别是getList和saveList,都加上事务注解:结果还是同上。

经验告诉我,当你的请求包含了提交事务的时候,你同时又读了数据,并且需要在controller或是view层懒加载数据,则会有问题,因为事务一提交就关闭了。

我唯一不能理解的是我先调用saveList,提交了事务,保存了数据,我再调用getList,按理应该重新生成事务,可是为什么到controller这里还是没有session了。

最后没办法,我把读写两个事情在controller层也分开为两个接口,在jsp里面做两次请求来处理。

总结一下:

1. service里面的方法如果不是对外的接口,加事务注解没有用

2. 一个请求里面如果包含了提交事务(非只读),同时又查询数据的话,查询的数据要立即加载,不能到view层再调用session去懒加载数据。


  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值