spring事务不生效问题

场景描述

数据库操作需求:先查询是否存在配置,如果不存在则insert至两张表中。数据库操作的Bean中有些一个查询两个insert,查询不需要事务,insert需要事务。开发时将三者封装至一个save方法中。代码如下

public boolean save(DTO dto) {
    // 查询配置
    PO po = query();
    save(dto, po);
}
@Transactional(rollbackFor = Exception.class)
public boolean insert(DTO dto, PO po) {
    boolean isSuccess = false;
    if (po == null) {
        po = insert(ConvertUtil.convert2Group(dto));
    }
    if (po.getId() != null) {
        Item item = new Item();
        item.setGroupId(po.getId());
        int effectCnt = insert(item);
        isSuccess = effectCnt > 0;
        if (!isSuccess) {
            log.error("insert packFullOrder failed ,packFullOrder={}", packFullOrder);
            throw new PackFullOrderException("保存待打包订单失败");
        }
    }
    return isSuccess;
}

事与愿违,调用save方法事务没有生效,但是调用insert方法事务是有效的。由于事务的实现是通过拦截器反射实现事务操作的bean,代理的方法如果没有事务注解属性的配置会导致调用的子方法的事务失效。

  1. save方法是切面的切入点,切入点判断当前方法不存在事务属性配置,于是没有开启事务
  2. 切面执行完拦截方法后直接调用切入点ReflectiveMethodInvocation.invokeJoinpoint。从源码中可以看到此处的调用是target实际实例的方法调用,而不是代理的bean,所以此时的insert的调用是没有切面的事务拦截器进行拦截增强的。
public Object proceed() throws Throwable {
	//	We start with an index of -1 and increment early.
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        // 反射调用实际实例方法
		return invokeJoinpoint();
	}
    // 事务拦截器拦截调用织入事务代码
	Object interceptorOrInterceptionAdvice =
			this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
		// Evaluate dynamic method matcher here: static part will already have
		// been evaluated and found to match.
		InterceptorAndDynamicMethodMatcher dm =
				(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
		if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
			return dm.interceptor.invoke(this);
		}
		else {
			// Dynamic matching failed.
			// Skip this interceptor and invoke the next in the chain.
			return proceed();
		}
	}
	else {
		// It's an interceptor, so we just invoke it: The pointcut will have
		// been evaluated statically before this object was constructed.
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

protected Object invokeJoinpoint() throws Throwable {
	return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}

总结

使用了事务的方法,如果通过同样的实例中非事务的方法调用,会导致事务注解的实例方法的事务会不生效

解决

  1. 为业务接口中每一个数据库操作增加事务注解
  2. 业务层单独调用查询方法后再去调用事务方法
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值