废话不说,先看代码 ↓
Controller:
/**
* @description:
* @author: wajn
* @create: 2020-04-25 19:32
**/
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("testsave")
public String save(){
return userService.save();
}
}
Service:
/**
* @description:
* @author: wajn
* @create: 2020-04-25 19:32
**/
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public String save(){
System.out.println("处理业务代码");
System.out.println("调用当前的handler方法");
return handler();
}
@Transactional(rollbackFor = Exception.class)
public String handler(){
User user = new User();
user.setName("handler 1 " + UUID.randomUUID().toString());
userRepository.save(user);
User user2 = new User();
user2.setName("handler 2 " + UUID.randomUUID().toString());
userRepository.save(user2);
System.out.println("模拟报错::::=>" + 1/0);
return "处理成功";
}
}
Repository:
/**
* @description:
* @author: wajn
* @create: 2020-04-25 19:32
**/
public interface UserRepository extends JpaRepository<User, Integer> {
}
发挥想象, 你觉得user
和user2
这两个对象保存到数据库了还是回滚事务了.
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
也许结果 超乎你想象:
对,没错 两个对象已经入库了:
你可能在想,明明我加了事务呀. 怎么可能入库. 王德发???
要解决这个问题,我们得必须看源代码怎么处理的.毕竟解铃还得系铃人.
我们看org.springframework.aop.framework.AdvisedSupport类的这个方法:
该方法中会从调用方法中获取@Transactional注解,如果有该注解,则启用事务,否则不启用。有了注解才会调用下面这个方法.
org.springframework.transaction.interceptor.TransactionInterceptor
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}