下面例子中,事务方法doOtherThing新起了线程执行。这样会导致内外事务不在同一个线程中,获取到的数据库连接不一样,从而是两个不同的事务。如果想doOtherThing方法中抛了异常,add方法也回滚是不可能的。
@Slf4j@Servicepublic class UserService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate RoleService roleService;@Transactionalpublic void add(UserModel userModel) throws Exception {userMapper.insertUser(userModel);new Thread(() -> {roleService.doOtherThing();}).start();}}@Servicepublic class RoleService {@Transactionalpublic void doOtherThing() {System.out.println("保存role表数据");}}
Spring事务源码是通过数据库连接来实现的,当前线程中保存了一个map,key是数据源,value是数据库连接。在不同的线程中拿到的数据库连接也不同。我们说的同一个事务,其实是指同一个数据库连接,只有拥有同一个数据库连接才能同时提交和回滚。
private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources");
