Spring事务失效不回滚的几种案列

简介

Spring使用AOP代理实现事务,默认情况下只捕获 RuntimeException 的异常

概况

  1. 抛出非RuntimeException
  2. 若异常被捕获且不抛出,则不会回滚
  3. 不经Spring代理,直接调用本类方法
  4. 未正确使用事物的propagation(传播)属性
  5. 方法被staticfinal非public方法修饰
  6. 业务类没有托管给Spring注册为Bean对象
  7. 切面的优先级在事物之前,需手动回滚异常
  8. 数据库使用了不支持事务的存储引擎,如:Mysql中的MyISAM
  9. 在多线程场景中,获取到的数据库连接是不一样的,即是不属于同一事务,则无法回滚
  10. 需要调用的业务类,在事物被声明之前注册成Bean对象,即优先级高于事物,导致事物失效

案列一

问题详情

一、抛出非RuntimeException

public void saveUser(User user) {
    try {
        userDao.save(user);
    } catch (Exception e) {
        //抛出非RuntimeException
        throw new IllegalAccessException();
    }
}

解决方案

一、申明回滚异常

//通过注解rollbackFor,申明回滚的异常
@Transactional(rollbackFor = Exception.class)
public void saveUser(User user) {
    try {
        userDao.save(user);
    } catch (Exception e) {
        throw new IllegalAccessException();
    }
}

案列二

问题详情

一、若异常被捕获且不抛出,则不会回滚

public void saveUser(User user) {
    try {
        userDao.save(user);
    } catch (Exception e) {
        logger.info("保存失败:错误信息为:" + e);
    }
}

解决方案

一、显式抛出异常

public void saveUser(User user) {
    try {
        userDao.save(user);
    } catch (Exception e) {
        logger.info("保存失败:错误信息为:" + e);
        //显式抛出异常
        throw new RuntimeException();
    }
}

二、手动回滚事物

public void saveUser(User user) {
    
    try {
        userDao.save(user);
    } catch (Exception e) {
        logger.info("保存失败:错误信息为:" + e);
        //手动回滚事物
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
    
} 

案列三

问题详情

一、不经Spring代理,直接调用本类方法

@Service
public class UserServiceImpl implements UserService {
        
    public boolean saveUser(User user) {
        //不经Spring代理,直接调用本类方法
        return this.save(user);
    }
    
    @Transactional(rollbackFor = Exception.class)
    public boolean save(User user) {
        return userDao.save(user);
    }

}

解决方案

一、使用AspectJ 代理

1. 在启动类上开启代理

@SpringBootApplication
//启用AspectJ 代理
@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
public class UserApplication {

    public static void main(String[] args) {
        SpringApplication.run(UserApplication.class, args);
    }

}

2. 使用代理调用本地方法

@Service
public class UserServiceImpl implements UserService {
    
    public boolean saveUser(User user) {
        //使用AspectJ 代理
        return ((UserService) (AopContext.currentProxy())).save(user);
    }

    
    @Transactional(rollbackFor = Exception.class)
    public boolean save(User user) {
        return userDao.save(user);
    }

    
}    

案列四

问题详情

一、未正确使用事物的propagation(传播)属性

@Transactional(propagation = Propagation.NOT_SUPPORTED)

解决方案

一、使用默认propagation(传播)属性

@Transactional(propagation = Propagation.REQUIRED)

案列八

JPA配置InnoDB存储引擎

spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

你可能感兴趣的:(Spring事务失效不回滚的几种案列)