准备接口
import java.util.List;
public interface IOperate<T> {
void add(T t);
List<T> selectALl();
}
接口实现类
@Component
public class LogdtfService implements IOperate<LOGDTF> {
@Autowired
private LOGDTFMapper logdtfMapper;
@Transactional(rollbackFor = Exception.class)
@Override
public void add(LOGDTF logdtf) {
logdtfMapper.insert(logdtf);
}
@Override
public List<LOGDTF> selectALl() {
// TODO
return null;
}
}
@Component
public class KorekfService implements IOperate<KOREKF> {
@Autowired
private KOREKFMapper korekfMapper;
@Transactional(rollbackFor = Exception.class)
@Override
public void add(KOREKF korekf) {
korekfMapper.insert(korekf);
// ❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗手动模拟异常❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗
int a = 1 / 0;
}
@Override
public List<KOREKF> selectALl() {
// TODO
return null;
}
}
⏹logser.add()
和korser.add()
方法均被添加了事务,我们在korser.add()
中模拟了异常,由于这两个事务方法被test()
方法调用,且test()
方法也被添加了事务,也就是说logser.add()
和korser.add()
中的事务是子事务,从属于test()
中的总事务,当总事务方法或者任何一个子事务方法出现异常的时候,整体都会回滚.
public class A {
@Autowired
private LogdtfService logser;
@Autowired
private KorekfService korser;
@Transactional(rollbackFor = Exception.class)
public void test( ) {
LOGDTF logdtf = new LOGDTF();
logdtf.setPgid("jmw1");
logser.add(logdtf);
KOREKF korekf = new KOREKF();
korekf.setKorTantono(new BigDecimal(33));
korekf.setKorKaisyacd(new BigDecimal(118));
korekf.setKorTekinen(new BigDecimal(202203));
korekf.setKorKaisyanm("jmw0321");
korser.add(korekf);
}
}
public class A {
@Autowired
private LogdtfService logser;
@Autowired
private KorekfService korser;
@Transactional(rollbackFor = Exception.class)
public void test( ) {
LOGDTF logdtf = new LOGDTF();
logdtf.setPgid("jmw1");
logser.add(logdtf);
// 捕获子事务异常
try {
KOREKF korekf = new KOREKF();
korekf.setKorTantono(new BigDecimal(33));
korekf.setKorKaisyacd(new BigDecimal(118));
korekf.setKorTekinen(new BigDecimal(202203));
korekf.setKorKaisyanm("jmw0321");
korser.add(korekf);
} catch (Exception e) {
System.out.println(e);
}
// 进行其他操作......
}
}
在test()
方法中调用korser.add()
方法时,添加try...catch
,当korser.add()
出现异常时,会出现Transaction rolled back because it has been marked as rollback-only
异常,此时整体都会回滚
korser.add()
方法使用了propagation = Propagation.NESTED
事务传播行为
@Component
public class KorekfService implements IOperate<KOREKF> {
@Autowired
private KOREKFMapper korekfMapper;
// ❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗使用Propagation.NESTED事务传播行为
@Transactional(rollbackFor = Exception.class, propagation = Propagation.NESTED)
@Override
public void add(KOREKF korekf) {
korekfMapper.insert(korekf);
// ❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗手动模拟异常❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗❗
int a = 1 / 0;
}
@Override
public List<KOREKF> selectALl() {
// TODO
return null;
}
}
korser.add()
方法添加了try...catch
public class A {
@Autowired
private LogdtfService logser;
@Autowired
private KorekfService korser;
@Transactional(rollbackFor = Exception.class)
public void test( ) {
LOGDTF logdtf = new LOGDTF();
logdtf.setPgid("jmw1");
logser.add(logdtf);
try {
KOREKF korekf = new KOREKF();
korekf.setKorTantono(new BigDecimal(33));
korekf.setKorKaisyacd(new BigDecimal(118));
korekf.setKorTekinen(new BigDecimal(202203));
korekf.setKorKaisyanm("jmw0321");
korser.add(korekf);
} catch (Exception e) {
System.out.println(e);
}
// 进行其他操作......
}
}
korser.add()
外部的try...catch
去掉,则整体回滚Propagation.NESTED
可以让事务部分回滚savepoint
。 如果这个嵌套事务失败, 我们将回滚到此 savepoint
。 嵌套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。logser.add()
方法执行完毕时,会生成一个savepoint
,此savepoint
中存储着logser.add()
的执行结果(向数据库中插入了X条数据),当korser.add()
嵌套事务的方法执行失败时,我们回滚到生成的savepoint
中,由于我们对其进行了try...catch
,因此异常并不会被抛到主方法中,所以logser.add()
会执行成功,从而实现了事务的部分回滚.参考资料:
1.Spring事务管理报错:Transaction rolled back because it has been marked as rollback-only
2.spring 事务传播行为之嵌套事务NESTED细节
3.Spring嵌套事务
4.事务之六:spring 嵌套事务
5.spring 嵌套事务
6.Spring 事务失效常见的几种情况