在开发中可能遇到下面的代码
@Service
public class UserServiceImpl implements UserService{
@Override
@Transactional
public void saveUser() {
//做一些其他操作
test();
throw new RuntimeException("errror");
}
@Transactional(propagation =Propagation.REQUIRES_NEW)
@Override
public void test() {
User user = new User();
user.setId(2);
user.setUserName("xxxx");
user.setPassword("23232");
userRepository.save(user);
}
}
在一个事物中开启了一个事物,这个事物会挂起单前事物然后创建一个新的事物,第一个事物抛出异常不影响这个新创建的事物。我们期待的结果是User的对象能够正确的保存到数据库,但是最后的结果是数据并没有保存到数据库。这个为什么嘞?
Spring Bean创建的生命周期
- class(UserService.class)
- 推断构造方法
- 实例化
- 对象
- 属性填充(依赖注入) (先byType在byName)
- 初始化(InitializingBean->afterPropertiesSet)
- AOP(1. 找出所有的切面 2. 查看UserService是否有切点)
- 代理对象(通过切点创建代理对象返回)
- Bean对象
可以看出在调用代理对象UserService的saveUser这个目标方法的时候,spring只能识别saveUser上面的注解,对于test方法就是一个普通方法,上面的事物注解根本就是无效的。并没有开启一个新的事物。
解决方法
不要直接调用test方法,要调用一个代理对象的test方法。调用通过spring 构造好的对象的test方面。这样就会创建一个新的事物,并且保存成功。
@Service
public class UserServiceImpl implements UserService{
@Autowired
private UserService proxy;
@Override
@Transactional
public void saveUser() {
//做一些其他操作
proxy.test();
throw new RuntimeException("errror");
}
@Transactional(propagation =Propagation.REQUIRES_NEW)
@Override
public void test() {
User user = new User();
user.setId(2);
user.setUserName("xxxx");
user.setPassword("23232");
userRepository.save(user);
}
}