导致这个异常的原因是:

在使用Spring事务的过程中,A方法调用B方法,A B方法都操作了数据库,B方法由于抛出异常需要回滚,而A方法没有抛出异常所以要执行提交,而Spring默认的事务传播行为是Propagation.REQUIRED,即A B方法处于同一个事务中,一个要回滚一个要提交,这样就导致了冲突。

导致异常的代码样例如下:

@Service
public class StudentServiceImpl implements IStudentService{
private StudentMapper studentMapper;

@Override
@Transactional
public void save() {
Student stu = new Student();
stu.setName("李四");
studentMapper.insert(stu);
try {
((IStudentService)AopContext.currentProxy()).save2();
} catch (Exception e) {
e.printStackTrace();
}
}

@Override
@Transactional
public void save2() {
Student stu = new Student();
stu.setName("王五");
studentMapper.insert(stu);
throw new RuntimeException("新增王五失败");
}
}

调用方式如下:

@SpringBootTest
@RunWith(SpringRunner.class)
class SpringbootTestApplicationTests {
@Autowired
private IStudentService iStudentService;
@Test
void test() {
iStudentService.save();
}
}

解决办法:

方法1:将Spring事务传播行为设置为Propagation.REQUIRES_NEW,这样A B方法就能处于不同的事务中了,彼此互不影响。只需要在save2方法上打上@Transactional(propagation = Propagation.REQUIRES_NEW)。

再次运行程序,会发现数据库只新增了李四,而王五没有新增。

方法2:在A方法中调用B方法时,不要捕获B方法抛出的异常,那样即使A B方法处于同一个事务中,但它们都是回滚的,不会出现冲突。

再次运行程序,会发现数据库中李四和王五都没有新增。