题目:在如下代码中,当调用insertA方法时,如果insertB插入b表的时候有异常,能否保证insertA()中的a表插入成功,如果不能,应该如何修改?

问题:

在如下代码中,当调用insertA方法时,如果insertB插入b表的时候有异常,能否保证insertA()中的a表插入成功,如果不能,应该如何修改?

@Service
@Transactional
public class TestService {

	@Autowired
	private JdbcTemplate jt;
	
	public void insertA(){
		jt.execute("insert into a(m,n) values(1,2)");
		insertB();
	}

	public void insertB(){
		jt.execute("insert into b(h,i) values(1,2)");
	}
}

解释:

不能保证insertA()中的a表插入成功,因为@Transactional加载类上,相当于加载了该类的每一个方法上

首先明确一点“同一个对象内的事务方法互相调用会导致被调用方的事务失效”,我们都知道事务使用代理对象来完成事务功能,如果在insertA()方法中直接调用同一个对象(@Service表示把当前类交给了spring管理,而spring默认使用单例模式创建对象,因此调用方法的时候使用的会是同一个对象)中的insertB()方法,这和直接把insertB()方法的代码写在insertA()方法中是一致的,这也会导致绕过了代理对象,因此这种调用方式会导致insertB()方法上的事务失效

如果我们想让事务生效,我们可以调用暴露出来的代理对象,那我们就不能使用默认JDK动态代理了,而是要使用aspectj动态代理,以后所有的动态代理都是由aspectj来创建,即使没有借口,也可以进行动态代理

根据题意要求,insertB()方法不能和insertA()方法共用一个事务,所以我们要改变insertB()方法的事务传播行为,默认事务传播行为是Propagation.REQUIRED,常见事务传播行为如下所示:

在这里插入图片描述

答案:

1、引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2、在主启动类上使用注解开启aspectj动态代理,并且暴露代理对象

@EnableAspectJAutoProxy(exposeProxy = true)

3、使用aspectj代理对象来调用本对象中的事务方法,并且改变insertB()方法上的事务传播行为

@Service
@Transactional
public class TestService {

	@Autowired
	private JdbcTemplate jt;
	
	public void insertA(){
		jt.execute("insert into a(m,n) values(1,2)");
		// 1、拿到当前代理对象
		TestService testService = (TestService)AopContext.currentProxy();
		// 2、使用代理对象调用insertB()事务方法
		testService.insertB();
	}

	// 3、改变insertB()方法的事务传播行为,默认事务传播行为是Propagation.REQUIRED,代表继承父类的事务传播行为,即被调用方法和调用方法在同一个事务中,遵循ACID特性,根据题意要求"我们要保证insertB()方法出现异常的时候,insertA()方法中的a表插入成功",因此我们就不能让insertA()和insertB()方法使用同一个事务,因此我们改变insertB()方法的事务传播行为是"创建新事务"
	@Transactional(propagation = Propagation.REQUIRES_NEW)
	public void insertB(){
		jt.execute("insert into b(h,i) values(1,2)");
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值