spring事务失效

一,事务失效的12种场景

 二,@Transactional注解的时效场景(附加代码)

一、正常情況

 事务生效报错数据无变化

二、try/catch 导致事务失效

@Transactional 执行流程是: @Transactional 会在方法执行前,会自动开启事务;在方法成功执行完,会自动提交事务;如果方法在执行期间,出现了异常,那么它会自动回滚事务。

 

 导致结果:

能看出来事务并没有生效 

 

三、调用类内用的 @Transactional 方法

 执行结果:

上述代码在添加用户之后即使遇到了异常,程序也没有执行回滚,这是因为 @Transactional 是基于 Spring AOP 实现的,而 Spring AOP 又是基于动态代理实现的,而当调用类内部的方法时,不是通过代理对象完成的,而是通过 this 对象实现的,这样就绕过了代理对象,从而事务就失效了。

解决办法:


1、自注入

@Service
public class UserInfoService {
   @Autowired
    private UserInfoService userInfoService;
    public void justUpdate(){
        userInfoService.updateUser2();
    }
    @Transactional(rollbackFor = Exception.class)
    public void updateUser2() {

    }
}

2、Spring上下文

@Service
public class UserInfoService {
    ApplicationContext applicationContext;
    public void justUpdate(){
           UserInfoService userInfoService = (UserInfoService) applicationContext.getBean("userInfoService");
        userInfoService.updateUser2();
    }
    @Transactional(rollbackFor = Exception.class)
    public void updateUser2() {
    }
}

3、获取他的代理类,直接调用代理类

@Service
public class UserInfoService {
    public void justUpdate(){
           ((UserInfoService) AopContext.currentProxy()).updateUser2();
    }
    @Transactional(rollbackFor = Exception.class)
    public void updateUser2() {
    }
}

------------------------以下属于copy其他博客的场景这里我就不一一示范了---------------------------

四、多数据源事物配置问题

项目中没有配置事务管理器,需要在配置类或者配置文件中配置,因为项目是多数据源的,所以要区别配置不同数据源的事务管理器,如下:

@Primary
    @Bean(name = "db1")
    public DataSource getDataSource() {
        return createDataSource();
    }
    @Bean(name = "db1TransactionManager")
    public PlatformTransactionManager txManager(@Qualifier("db1") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }


   @Bean(name = "db2")
   public DataSource getDataSource() {
       return buildDataSource();
   }
   @Bean(name = "db2TransactionManager")
   public PlatformTransactionManager txManager(@Qualifier("db2") DataSource dataSource) {
       return new DataSourceTransactionManager(dataSource);
   }

可以看到,两个事务管理器配置了不同的beanName,接下来只需要 在需要事务控制的位置加上该事务管理器的name就可以完美解决!

 @Override
   @Transactional(value = "db1TransactionManager",rollbackFor = Exception.class)
   public int updateOrInsert(BaseRequest<BankTemplateDto> param) {
      ...
   }

五、新开启一个线程

如下的方式deleteUserA()也不会回滚,因为spring实现事务的原理是通过ThreadLocal把数据库连接绑定到当前线程中,新开启一个线程获取到的连接就不是同一个了,例如:

@Transactional
public void deleteUser() throws MyException{
    userMapper.deleteUserA();
    try {
        
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    new Thread(() -> {
        int i = 1/0;
        userMapper.deleteUserB();
    }).start();    
}

六、事务传播属性设置错误

注意传播属性的设置,一般情况下,propagation属性无需配置。会使用默认配置,即:PROPAGATION_REQUIRED,有些propagation属性会导致事务不会触发,一定要注意:

PROPAGATION_SUPPORTS: 如果存在事务,则进入事务;否则,以非事务方式运行。

PROPAGATION_NOT_SUPPORTED: 如果存在事务,则挂起事务,并以非事务方式运行。
PROPAGATION_NEVER: 以非事务形式运行,如果存在事务,则抛出异常。

七、注解的方法是否为public

@Transactional
private void deleteUser() throws MyException{
    userMapper.deleteUserA();
    int i = 1/0;
    userMapper.deleteUserB();
}

idea直接会给出提示Methods annotated with ‘@Transactional’ must be overridable ,原理很简单,private修饰的方式,spring无法生成动态代理,AOP代理分别在intercept()和invoke()方法判断是否进行事务拦截,这两个方法都会间接调用AbstractFallbackTransactionAttributeSource类的computeTransactionAttribute方法来获取事务控制的相关属性。这其中有以下一段代码

    /**
     * Same signature as {@link #getTransactionAttribute}, but doesn't cache the result.
     * {@link #getTransactionAttribute} is effectively a caching decorator for this method.
     * <p>As of 4.1.8, this method can be overridden.
     * @since 4.1.8
     * @see #getTransactionAttribute
     */
    protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
        
        if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
            return null;
        }
    
  }

这段代码会导致no-public的方法无法进入事务控制,所以一定要确保自己需要进行事务控制的方法包含public修饰符

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值