声明式事务--调用链上游方法如不开启事务需避坑

新建一个springboot项目进行事务测试,加入jpa依赖,创建数据库test,新增表User,就三个字段id,username,password.

测试1:同一个类中,加了@Transactional注解的方法调用没加注解的方法
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Transactional
@Override
public void add(){
addActually();
}
private void addActually(){
User user = new User(1,"zhangsan","pwd");
userRepository.save(user);
throw new RuntimeException();
}
}

测试结果:不论在哪个方法中抛出异常,事务都能正常回滚。


测试二:同一个类中,未加注解的方法调用加了@Transactional注解的方法

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserRepository userRepository;

    @Override
    public void add(){
        addActually();
    }

    @Transactional(propagation = Propagation.MANDATORY)
    public void addActually(){
        User user = new User(1,"zhangsan","pwd");
        userRepository.save(user);
        throw new RuntimeException();
    }
}

测试结果:无论在哪个方法中抛出异常,事务都没有回滚。

这里我特意说明了事务的传播特性为MANDATORY,用于测试这里@Transactional注解是否生效,结果是还是抛出我显示编码的RuntimeException,而不是IllegalTransactionStateException。

说明addActually()方法的@Transactional注解完全被忽略了。

测试3:类A的未加事务注解的方法调用类B的加了@Transactional注解的方法

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private CopiedUserService copiedUserService;
    @Override
    public void add(){
        copiedUserService.addActually();
    }
}

@Service
public class CopiedUserServiceImpl implements CopiedUserService {
    @Autowired
    private UserRepository userRepository;
    @Transactional
    @Override
    public void addActually(){
        User user = new User(1,"zhangsan","pwd");
        userRepository.save(user);
        throw new RuntimeException();
    }
}

测试结果:事务正常回滚。

结论:为所有需要开启事务的方法及同一个类中上游调用方法都开启事务。

编程式事务或不在同一个类中无需这么做,猜想这是与aop的代理机制相关的。下次再继续分析。

猜你喜欢

转载自www.cnblogs.com/lvsunshine21/p/10460080.html
今日推荐