今天在测试事务的传播机制的时候,发现了一个问题。我在service里面写了两个方法,想分别执行不同的事务,结果发现好像事务没有起到作用一样。错误代码如下:
@Component
public class PersonService {
@Autowired
private PersonDao personDao;
public void saveAllPersonsMessage() {
this.saveVIPPersonMessage();
this.savePersonMessage();
}
public void saveVIPPersonMessage() {
Person person = new Person();
person.setName("VIP用户");
person.setAge(50);
personDao.save(person);
}
@Transactional(propagation = Propagation.REQUIRED)
public void savePersonMessage() {
this.savePersonMessage1();
int a = 1 /0 ;
this.savePersonMessage2();
}
public void savePersonMessage2() {
Person person = new Person();
person.setName("普通用户2");
person.setAge(30);
personDao.save(person);
}
public void savePersonMessage1() {
Person person = new Person();
person.setName("普通用户1");
person.setAge(19);
personDao.save(person);
}
}
自己设想的是只插入一条VIP用户,结果测试之后发现表里插入了VIP和普通用户1,两条数据。瞬间懵逼了,难道savePersonMessage()这个方法上的事务没起到作用???
为啥会这样,然后就一顿百度,终于找到了根本原因:
调用方法saveVIPPersonMessage() 和 savePersonMessage()是通过实例对象调用的,而非Spring代理的Bean。 内部调用时,被调用方法的事务声明将不起作用。换句话说,你在某个方法上声明它需要事务的时候,如果这个类还有其他开发者,你将不能保证这个方法真的会在事务环境中。再换句话说,Spring的事务传播策略在内部方法调用时将不起作用。不管你希望某个方法需要单独事务,是RequiresNew,还是要嵌套事务,要Nested,等等,统统不起作用。
好了,既然找到原因了,那就开始修改代码,正确代码如下:
@Component
public class PersonService {
@Autowired
private PersonDao personDao;
@Autowired
private PersonService personService;
public void saveAllPersonsMessage() {
personService.saveVIPPersonMessage();
personService.savePersonMessage();
}
public void saveVIPPersonMessage() {
Person person = new Person();
person.setName("VIP用户");
person.setAge(50);
personDao.save(person);
}
@Transactional(propagation = Propagation.REQUIRED)
public void savePersonMessage() {
this.savePersonMessage1();
int a = 1 /0 ;
this.savePersonMessage2();
}
public void savePersonMessage2() {
Person person = new Person();
person.setName("普通用户2");
person.setAge(30);
personDao.save(person);
}
public void savePersonMessage1() {
Person person = new Person();
person.setName("普通用户1");
person.setAge(19);
personDao.save(person);
}
}
好了,测试结果就跟预想的一样了,只插入了一条VIP用户的数据。