springboot 默认事务 代码示例
Ⅰ同一个类内默认传播行为的调用
1.1 方法addTeacher带默认传播行为的事务调用没事务的方法updateTeacher
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void addTeacher(String name, String code) {
try {
Teacher teacher = new Teacher(name, code);
mapper.insert(teacher);
this.updateTeacher("起飞", code);
log.info("添加用户结束");
} catch (Exception e) {
log.error("出现异常 e:{}", e.getMessage());
e.printStackTrace();
}
}
public void updateTeacher(String name, String code) {
Teacher teacher = mapper.selectOne(Wrappers.<Teacher>lambdaQuery().eq(Teacher::getCode, code));
if (teacher != null) {
teacher.setName(name);
mapper.updateById(teacher);
log.info("更新完成");
}
if ("起飞".equals(name)) {
throw new RuntimeException("名称不合法");
}
}
debug发现 方法updateTeacher可以查询到 用户,但是方法addTeacher尚未提交的事务,说明方法updateTeacher已经加入到调用者的事务中
可以看到数据库尚未更新未提交的事务数据继续往下走,当代码走到这里,查询数据库中等待锁的事务,发现没有,查询数据库运行中的事务,发现就只有一个,就证实了已经加入到调用者事务了
只有等方法addTeacher执行完毕,才可以看到数据库的修改
1.2 方法addTeacher带默认传播行为的事务调用有默认事务的方法updateTeacher
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void addTeacher(String name, String code) {
Teacher teacher = new Teacher(name, code);
mapper.insert(teacher);
log.info("添加用户");
updateTeacher("起飞", code);
log.info("添加用户结束");
}
@Transactional(propagation = Propagation.REQUIRED)
public void updateTeacher(String name, String code) {
Teacher teacher = mapper.selectOne(Wrappers.<Teacher>lambdaQuery().eq(Teacher::getCode, code));
if (teacher != null) {
teacher.setName(name);
mapper.updateById(teacher);
log.info("更新完成");
}
}
我们会发现,和updateTeacher没有加@Transactional是一莫一样的效果,其实addTeacher方法中直接调用updateTeacher(“起飞”, code)方法是不会触发到updateTeacher方法的事务的(正常情况没有影响,当出现异常的时候没有事务的updateTeacher方法进行的操作将不会回滚),因为直接调用并不是spring代理出来的对象是不会经过那个@Transactional注解的,我们需要稍微改动一下
updateTeacher(“起飞”, code);改成下面的形式即可
this.updateTeacher(“起飞”, code);
改动后效果其实和上面两种情况一致,因为事务传播行为是 REQUIRED(如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值),在执行updateTeacher时已经存在事务了,就加入调用者事务
Ⅱ同一个类内默认传播行为异常回滚
2.1 捕获异常
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void addTeacher(String name, String code) {
try {
Teacher teacher = new Teacher(name, code);
mapper.insert(teacher);
this.updateTeacher("起飞", code);
log.info("添加用户结束");
} catch (Exception e) {
log.error("出现异常 e:{}", e.getMessage());
e.printStackTrace();
}
}
public void updateTeacher(String name, String code) {
Teacher teacher = mapper.selectOne(Wrappers.<Teacher>lambdaQuery().eq(Teacher::getCode, code));
if (teacher != null) {
teacher.setName(name);
mapper.updateById(teacher);
log.info("更新完成");
}
if ("起飞".equals(name)) {
throw new RuntimeException("名称不合法");
}
}
根据默认的事务传播机制,updateTeacher是加入addTeacher事务的,事务中用于已经被修改了updateTeacher修改了,但是updateTeacher抛出异常被addTeacher捕获之后addTeacher却没有回滚
稍微改一下代码,让updateTeacher方法不进行数据库操作
public void updateTeacher(String name, String code) {
if ("起飞".equals(name)) {
throw new RuntimeException("名称不合法");
}
}
运行发现addTeacher真的没有回滚事务
再改一下代码,
给updateTeacher加上事务
会发现采用默认的传播机制,如果异常被捕获了,就不会事务回滚了。。。。。。
2.2 不捕获异常
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
@Override
public void addTeacher(String name, String code) {
Teacher teacher = new Teacher(name, code);
mapper.insert(teacher);
this.updateTeacher("起飞", code);
log.info("添加用户结束");
}
public void updateTeacher(String name, String code) {
if ("起飞".equals(name)) {
throw new RuntimeException("名称不合法");
}
}
执行完发现,数据被回滚了,数据库为空
改一下代码,updateTeacher加入事务,不操作数据库
@Transactional
public void updateTeacher(String name, String code) {
if ("起飞".equals(name)) {
throw new RuntimeException("名称不合法");
}
}
执行完,addTeacher修改的已经被回滚了
改一下代码,updateTeacher也操作数据库
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
@Override
public void addTeacher(String name, String code) {
Teacher teacher = new Teacher(name, code);
mapper.insert(teacher);
this.updateTeacher("起飞", code);
log.info("添加用户结束");
}
@Transactional
public void updateTeacher(String name, String code) {
Teacher teacher = mapper.selectOne(Wrappers.<Teacher>lambdaQuery().eq(Teacher::getCode, code));
if (teacher != null) {
teacher.setName(name);
mapper.updateById(teacher);
log.info("更新完成");
}
if ("起飞".equals(name)) {
throw new RuntimeException("名称不合法");
}
}
发现,数据库还是空的,会回滚updateTeacher、addTeacher操作,因为他们属于同一个事务