事务的传播属性(有坑点)自调用失效学习笔记

事务传播性:

事务的传播属性一共有七种,如下。

1、PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。

2、PROPAGATION_SUPPORTS:自身不会开启事务,在事务范围内则使用相同事务,否则不使用事务。‘

3、PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。

4、PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。

5、PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

6、PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。

7、PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

而在实际的应用总,只有PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED这三种是常用的。而第二三种很类似,PROPAGATION_REQUIRES_NEW是无论如何,子方法都会创建一个事务来管理。而PROPAGATION_NESTED则是应用了数据库的保存点技术,和调用它的方法共用同一个事务管理器。

这里有一个坑点,外部经过spring容器调用service的方法事务才生效,service类内部方法间相互调用事务不生效,也就是传说中的自调用失效问题。主要原因是 Spring数据库事务的约定,其实现原理是AOP,而AOP的原理是动态代理,在自调用的过程中,是类自身的调用,而不是代理对象去调用,那么就不会产生AOP,这样 Spring就不能把你的代码织入到约定的流程中,于是就产生了现在看到的失败场景。为了克服这个问题,我们可以用一个 Service去调用另一个 Service,这样就是代理对象的调用, Spring才会将你的代码织入事务流程。当然也可以从 Spring loc容器中获取代理对象去启用AOP。下面我粘了一段代码,通过这种方式,再ioc容器中获取代理对象就可以解决事务传播失效的问题。(具体对于异常是否要捕获,是否要继续抛出,则完全看你业务的需求。)

/**
 * 

* 服务类 *

* * @author alin * @since 2018-12-29 */ public interface ICityService extends IService { public void insertAlin01(City city) throws Exception; public void insertAlin02() throws Exception; }
@Service
public class CityServiceImpl extends ServiceImpl implements ICityService {

    @Autowired
    private CityMapper cityMapper;
    @Autowired
    private IUserService userService;
    @Autowired
    private ICityService cityService;

    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED)
    public void insertAlin01(City city) throws Exception {
        cityMapper.insert(city);
        User user = new User();
        user.setName("new");
        user.setGender(1);
        try {
            cityService.insertAlin02();
        } catch (Exception e) {

        }
    }

    @Override
    @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRES_NEW)
    public void insertAlin02() throws Exception {
        City city = new City();
        city.setName("method2");
        city.setAge(2);
        city.setState(DateUtil.getStringDate());
        cityMapper.insert(city);
    }

}

这里只是粗略写了点个人想法,想深入了解一点建议看《深入浅出Spring Boot 2.x》第六章6.4节传播行为的相关讲解。

你可能感兴趣的:(mysql)