Spring事务回滚实战

一、前置知识

1、Java异常中,Throwable是最顶层的父类,有Error和Exception两个子类
2、Exception分为运行时异常(RuntimeException及其子类)和非运行时异常(Exception子类中,除了RuntimeException及其子类之外的类)
3、使用spring的@Transactiona开启事务,默认Error和RuntimeException及其子类才会回滚
4、@Transactiona默认传播行为是REQUIRED,如需配合其他传播行为测试,请查看:Spring事务传播行为实战

二、情况分析

1、遇到异常可能回滚

1.1、Error和RuntimeException及其子类的异常,数据回滚

// 回滚
@Transactional
public void add() {
	KsA ksA = new KsA();
	ksA.setName("林");
	ksAService.insert(ksA);
	throw new RuntimeException("运行报错啦");
}

1.2、非运行时异常,数据不回滚

// 不回滚
@Transactional
public void add() throws IOException {
	KsA ksA = new KsA();
	ksA.setName("林");
	ksAService.insert(ksA);
	throw new IOException();
}

2、异常捕获

2.1、针对当前方法异常捕获

// 不回滚
@Transactional
public void add() {
	KsA ksA = new KsA();
	ksA.setName("林");
	ksAService.insert(ksA);
	try {
		throw new RuntimeException("运行报错啦");
	} catch (RuntimeException e) {
		e.printStackTrace();
	}
}

2.2、针对跨方法异常捕获

针对跨方法捕获的异常,事务回滚,因为内部事务已经结束,确实是抛出了异常,经过AOP切面

@Transactional
public String insertForlanA(ForlanA forlanA) {
	try {
		forlanBService.insertForlanB(new ForlanB());
	} catch (Exception e) {
		e.printStackTrace();
		return "特定异常结果";
	}
	return "成功";
}

@Transactional
public String insertForlanB(ForlanB forlanB) {
	forlanBDao.insert(forlanB);
	int res = 1 / 0; //java.lang.ArithmeticException: / by zero
	return "成功";
}

3、指定异常进行回滚

3.1 RuntimeException及其子类异常

// 回滚
@Transactional(rollbackFor = NullPointerException.class)
public void add() {
	KsA ksA = new KsA();
	ksA.setName("林");
	ksAService.insert(ksA);
	int forlan = 1 / 0;
}

这里抛出的是ArithmeticException,但我们指定是NullPointerException才回滚,为什么还是回滚了呢?
其实这两个类都是继承RuntimeException,Spring本来就默认了RuntimeException及其子类也是回滚的

3.2 非运行时异常

我们为什么还要指定rollbackFor参数?我们来看看下面的情况

// 回滚
@Transactional(rollbackFor = IOException.class)
public void add() throws IOException {
	KsA ksA = new KsA();
	ksA.setName("林");
	ksAService.insert(ksA);
	throw new IOException();
}

我们从1.2得知,非运行时异常默认是不回滚,但我们可以通过指定rollbackFor参数来回滚
结论:是针对非运行时异常的,在原基础上拓展

4、指定异常不回滚

// 不回滚
@Transactional(noRollbackFor = ArithmeticException.class)
public void add() {
	KsA ksA = new KsA();
	ksA.setName("林");
	ksAService.insert(ksA);
	int forlan = 1 / 0;
}

5、指定部分代码回滚

// ks_a表数据插入成功,ks_b数据回滚
@Transactional
public void add() {
	KsA ksA = new KsA();
	ksA.setName("林");
	ksAService.insert(ksA);
	Object savepoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
	try {
		KsB ksB = new KsB();
		ksB.setAge(10);
		ksBService.insert(ksB);
		throw new RuntimeException("父方法报错");
	} catch (Exception e) {
		TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savepoint);
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring事务回滚是在Spring框架中提供的一种机制,用于在事务发生异常或错误时撤销已执行的操作,使数据回滚到事务开始之前的状态。在Spring中,有几种方式可以实现事务回滚。 首先是编程式事务,这种方式需要在代码中手动开启事务、手动提交和手动回滚。虽然可以灵活控制事务的执行,但代码变得冗长和重复。 其次是声明式事务,通过配置SpringAop来实现事务的控制,大大简化了编码的复杂性。需要注意的是,切入点表达式必须正确配置。 还有注解事务,直接在Service层的方法上加上@Transactional注解即可实现事务控制。这种方式相对简单,是我个人比较喜欢使用的方式。 通常情况下,事务回滚的原因是由于抛出了RuntimeException异常。在声明式事务和注解事务中,当被切面切中或者是加了注解的方法中抛出了RuntimeException异常时,Spring进行事务回滚。但如果抛出的异常不属于运行时异常,比如IO异常,事务是不回滚的。 常见的导致事务不回滚的原因有以下几种: 1. 声明式事务配置切入点表达式写错,没有切中Service中的方法。 2. Service方法中捕获了异常,但只是打印了异常信息而未手动抛出RuntimeException异常。 3. Service方法中抛出的异常不属于运行时异常,因为Spring默认情况下只回滚运行时异常。 以上是关于Spring事务回滚的一些介绍和常见原因。希望对您有所帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Spring事务管理——回滚(rollback-for)控制](https://blog.csdn.net/ryelqy/article/details/80019106)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [spring事务回滚机制你懂得多少?](https://blog.csdn.net/weixin_45985053/article/details/125958535)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员Forlan

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值