下面例子中,事务方法doOtherThing新起了线程执行。这样会导致内外事务不在同一个线程中,获取到的数据库连接不一样,从而是两个不同的事务。如果想doOtherThing方法中抛了异常,add方法也回滚是不可能的。

    1. @Slf4j
    2. @Service
    3. public class UserService {
    4. @Autowired
    5. private UserMapper userMapper;
    6. @Autowired
    7. private RoleService roleService;
    8. @Transactional
    9. public void add(UserModel userModel) throws Exception {
    10. userMapper.insertUser(userModel);
    11. new Thread(() -> {
    12. roleService.doOtherThing();
    13. }).start();
    14. }
    15. }
    16. @Service
    17. public class RoleService {
    18. @Transactional
    19. public void doOtherThing() {
    20. System.out.println("保存role表数据");
    21. }
    22. }

    Spring事务源码是通过数据库连接来实现的,当前线程中保存了一个map,key是数据源,value是数据库连接。在不同的线程中拿到的数据库连接也不同。我们说的同一个事务,其实是指同一个数据库连接,只有拥有同一个数据库连接才能同时提交和回滚。

    1. private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources");