@Transactional自调用失效问题
@Transactional在某些场景下会失效,我们把传播行为修改为REQUIRESNEW,也就是每次调用产生新的事务
@Transactional(isolation = Isolaton.READCOMMITTED, propagation = Propagation.REQUIRED)
public int insertUsers (List<User> userList) {
int count = 0;
for (User user : userList)
{
//调用自己类自身的方法,产生自调用问题
count += insertUser(user),
}
return count;
}
//传播行为为REQUIRESNEW每次调用产生新事务
@Override
@Transactional(isolation =Isolation.READ COMMITTED, propagation = PropagatonREQUIRESNEW)
publicntinsertUser (User user) {
return userDao.insertUser(user);
}
这是一个类自身方法之间的调用,我称之为自调用.
pring数据库事务约定其实原理是AOP,AOP的原理是在自调用的过程中是类自身的调用,而不是理对象去调用,那么就不会产生AOP,这样Spring就不能把你的代码织入到约定的流程中于是就产生了现在看到的失败场景。为了克服这个问题,需要用一个Service去调用另一Service这样就是将代理对象的调用,Spring会将你的代码织入事务流程。
或者改造代码:
@Au tow ired prvateUserDao userDao = null;
private ApplicatonContextapplicationContext = null;
//实现生命周期方法,设置IoC容器@Oerride
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Transactional(isolation = Isolaton.READCOMMITTED, propagation = Propagation.REQUIRED)
public int insertUsers (List<User> userList) {
int count = 0;
//从IOC容器中取代理对象
UserService userService = applicationContext.getBean(UserService.class);
for (User user : userList)
{
//调用自己类自身的方法,产生自调用问题
count += userService .insertUser(user),
}
return count;
}
//传播行为为REQUIRESNEW每次调用产生新事务
@Override
@Transactional(isolation =Isolation.READ COMMITTED, propagation = PropagatonREQUIRESNEW)
publicntinsertUser (User user) {
return userDao.insertUser(user);
}
从代码中我实现了ApplicationContextAware 接口setApplicationContext方法这样便够把IoC容器设置到这个类中来。于是在setUser方法中,我通过Io容器取了UserService口对象。但是请注意这将是一个理对象并且使用传播行为为REUIRES_NEW的insertUse方法,这样才可以运行功。
这样自调用的问题就克服了,只是这样代码需要依赖于Spring的API,这样会造成代码的侵入。