Spring事务失效场景

1、Service类没有被Spring管理

//@Service (注释了@Service)
public class xxxServiceImpl implements xxxService {

    @Transactional
    public void addxxx(TianLuo tianluo) {
       //...
    }
}

上面例子中,spring事务没有生效,因为Spring事务是由AOP机制实现的,也就是从Spring IOC 容器中获取bean 时,Spring 会为目标类创建代理,来支持事务的。但是@Service被注释后,你的service类都不是被spring 管理的,更不会创建代理来支持事务。

2、没有在Spring配置文件中启用事务管理器

@Configuration
public class AppConfig {
    // 没有配置事务管理器
}

@Service
public class MyService {
    @Transactional
    public void doSomething() {
        // ...
    }
}

没有在AppConfig中配置事务管理器,因为Spring无法创建事务代理对象,导致事务不生效。

如何解决呢?

@Configuration
public class AppConfig {
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }
}

@Service
public class MyService {
    @Transactional
    public void doSomething() {
        // ...
    }
}

如果是SpringBoot项目,默认会自动配置事务管理器并开启事务支持的。

3、事务方法被final、static关键字修饰

@Service
public class xxxServiceImpl  {

    @Autowired
    private xxxMapper xxxMapper;

    @Transactional
    public final void xxx(xxx xxx) {
        xxxMapper.save(xxx);
    }
}

一个方法被final或者static修饰,则该方法不能被子类重写,也就是说在该方法上进行动态代理,这会导致Spring无法生成事务代理对象来管理事务。

事务方法不要被final或者static修饰。

4、同一个类中,方法内部调用

@Service
public class xxxServiceImpl implements xxxService {

    @Autowired
    private xxxMapper xxxMapper;
    
    @Autowired
    private xxx1Mapper xxx1Mapper;
    
    public void addxxx(xxx xxx){
     // 调用内部的事务方法
     this.executeAddxxx(xxx);
   }

    @Transactional
    public void executeAddxxx(xxx xxx) {
        xxxMapper.save(xxx);
        xxx1Mapper.saveFlow(xxx);
    }
}

事务是通过Spring AOP代理来实现的,而在同一个类中,一个方法调用另一个方法时,调用方法直接调用目标方法的代码,而不是通过代理类去进行调用的。

可以新建多一个类,让调用方法分开在不同类中。
也可以在该service类中注入自己,或者通过AopContext.currentProxy()获取代理对象。

5、方法的访问权限不是public

@Service
public class xxxServiceImpl  {

    @Autowired
    private xxxMapper xxxMapper;

    @Transactional
    private void xxx(xxx xxx) {
        xxxMapper.save(xxx);
    }
}

spring事务方法xxx不是public,事务不生效。因为spring事务是由AOP机制实现的,AOP机制的本质就是动态代理,而动态代理的事务方法不是public的话,computeTransactionAttribute()方法就会返回null,也就是这时事务属性不存在了。可以看下AbstractFallbackTransactionAttributeSource的源码:

事务方法的访问权限必须得是public

6、数据库的存储引擎不支持事务

spring事务的底层,还是依赖于数据库本身的事务支持。在mysql中,MyISAM存储引擎是不支持事务的,InnoDB引擎才支持事务。因为在开发阶段设计表的时候,要确认你选择的存储引擎是支持事务的。

7、配置错误的@Transactional 注解

@Service
public class xxxServiceImpl  {

    @Transactional(readOnly = true)
    public void updateUser(User user) {
        userDao.updateUser(user);
    }
}

上述方法中使用了@Transactional注解,但是注解中的readOnly = true属于指示这是一个只读事务,因为在进行更新User实体的时候会抛出异常。

如何解决呢?
将readOnly = true改为false,或者移除@Transactional注解中的readOnly属性。

8、事务超时时间设置过短

@Transactional(timeout = 1)
public void doSomething() {
    //...
}

上面方法中,timeout属性被设置为1秒,这意味着如果事务在1秒内无法完成,则报事务超时了。

9、rollbackFor属性配置错误

@Transactional(rollbackFor = Error.class)
public void doSomething() {
    //...
}

rollbackFor属性指定的异常必须是Throwable或者子类。默认情况下,RuntimeException和Error两种异常都是会自动回滚的。但是因为上述的代码指定的rollbackFor = Error.class,但是抛出的异常又是Exception,而Exception和Error没有任何什么继承关系,因此事务就不生效。

大家也可以看一下Transactional注解的源码。

rollbackFor属性指定的异常与抛出的异常要匹配。
一般使用:@Transactional(rollbackFor=Exception.class)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值