你必须知道的@Transactional

Scroll Down
废话不说,先看代码 ↓

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> {

}

发挥想象, 你觉得useruser2这两个对象保存到数据库了还是回滚事务了.

















也许结果 超乎你想象:

对,没错 两个对象已经入库了:

image.png

你可能在想,明明我加了事务呀. 怎么可能入库. 王德发???
要解决这个问题,我们得必须看源代码怎么处理的.毕竟解铃还得系铃人.
我们看org.springframework.aop.framework.AdvisedSupport类的这个方法:
image.png
该方法中会从调用方法中获取@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);
	}