1.场景一:两个service类 ClassAServiceImpl ,ClassBServiceImpl; A类的testA调用B类的testB方法,A类中testA方法添加事务注解并且调用B类的testB方法时添加try catch,分析testB方法是否添加事务注解对程序的影响。
A类:
@Service
public class ClassAServiceImpl implements IClassAService {
private final IClassBService iClassBService;
@Autowired
public ClassAServiceImpl(IClassBService iClassBService){
this.iClassBService = iClassBService;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void testA() {
// 省略业务代码
try {
iClassBService.testB();
}catch (Exception e){
// 这里不抛出异常
}
}
}
B类:
@Service
public class ClassBServiceImpl implements IClassBService {
@Override
@Transactional(rollbackFor = Exception.class)
public void testB() {
int i = 1 / 0;
}
}
1. testB方法添加事务注解:
testA方法调用testB,testB抛出异常,然后testA方法中捕获异常,但是不抛出异常,最终程序异常。
异常信息:Transaction rolled back because it has been marked as rollback-only
异常解释:testA和testB方法上都添加了事务注解,这时应该存在两个事务,testA的主事务,testB的子事务,事务嵌套执行,当testB子事务发生异常时整个事务已经被标志为需要回滚,这时testA方法里捕获了异常没有抛出,没法进行事务回滚,和事务的标志状 态不一致,导致发生异常。
2.testB方法不添加事务注解:
testA方法调用testB,正常执行。
解释:这时testB会加入到testA的事务中,相当于只存在一个事务,不存在子事务和主事务的说法,只有当testA事务抛出异常时,整个事务才会被标志为回滚状态。
2.场景二:当testA和testB都在A类中时
@Service
public class ClassAServiceImpl implements IClassAService {
@Override
@Transactional(rollbackFor = Exception.class)
public void testA() {
// 省略业务代码
try {
testB();
}catch (Exception e){
// 这里不抛出异常
}
}
@Transactional(rollbackFor = Exception.class)
void testB(){
// 这里的testB方法没有通过实现接口重写,就是类中一个普通方法
int i = 1 / 0;
}
}
1.这时无论testB方法是否添加事务注解,代码都会正常运行。
解释: 同一个类的方法直接调用 testB的事务注解会失效。
2. 或许有人说通过代理调用就可以使事务注解生效:
@Service
public class ClassAServiceImpl implements IClassAService {
@Override
@Transactional(rollbackFor = Exception.class)
public void testA() {
// 省略业务代码
try {
((ClassAServiceImpl) AopContext.currentProxy()).testB();
}catch (Exception e){
// 这里不抛出异常
}
}
@Transactional(rollbackFor = Exception.class)
void testB(){
// 这里的testB方法没有通过实现接口重写,就是类中一个普通方法
int i = 1 / 0;
}
}
结论: 代码还是正常运行。
解释: AopContext.currentProxy()是获取当前类的代理类(类实现了接口就使用jdk动态代理,否则就是cglib),这里ClassAServiceImpl实现了接口采用jdk动态代理,但是这里testB方法是类的普通方法,没有通过实现接口的方式在类中重写,导致代理失效。
3.testB方法实现接口
@Service
public class ClassAServiceImpl implements IClassAService {
@Override
@Transactional(rollbackFor = Exception.class)
public void testA() {
// 省略业务代码
try {
((IClassAService) AopContext.currentProxy()).testB();
}catch (Exception e){
// 这里不抛出异常
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void testB() {
// 实现接口方式
int i = 1 / 0;
}
}
这时方法运行就会抛出异常:Transaction rolled back because it has been marked as rollback-only
解决方法:去掉testB方法的事务注解即可。