spring-事务和锁顺序的问题

spring-事务和锁顺序的问题

经常会在事务中方法中使用锁

举个例子

@Service
public class TrxService {

    @Autowired
    ApplicationEventPublisher eventPublisher;

    private ReentrantLock lock = new ReentrantLock(false);

    @Transactional
    public void order() {
        lock.lock();
        System.out.println("get lock");
        try {
            System.out.println("do order...");
            eventPublisher.publishEvent(new OrderEvent(this, "temp"));
            System.out.println("execute finally");
        } finally {
            System.out.println("release lock");
            lock.unlock();
        }
    }


    
    /**
     * 事务监听器,监听事务提交时的事件
     * @param orderEvent
     */
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, classes = OrderEvent.class)
    public void onUserRegisterEvent(OrderEvent orderEvent) {
        System.out.println("orderEvent: " + orderEvent.getParam());
    }


    @SimpleLock
    @Transactional
    public void orderAop() {
        System.out.println("do order...");
        eventPublisher.publishEvent(new OrderEvent(this, "temp"));
        System.out.println("execute finally");
    }
}

@Getter
@Setter
public class OrderEvent extends ApplicationEvent {
    private String param;

    public OrderEvent(Object source, String param) {
        super(source);
        this.param = param;
    }
}

测试:

@RestController
public class TrxController {

    @Autowired
    private TrxService trxService;

    @GetMapping("/trx")
    public String trx(){
        trxService.order();
        return "success";
    }


    @GetMapping("/trx/aop")
    public String trxAop(){
        trxService.orderAop();
        return "success";
    }
}

请求 /trx, 返回:

get lock
do order...
execute finally
release lock
orderEvent: temp

可以发现, 在一个事务方法 中,事务的提交是在释放锁之后的,这里在高并发环境就很容易出现问题,比如使用分布式锁的情况

解决方案

  • 将锁的获取和释放单独放在另外 一个方法中,然后调用目标事务方法,这样就能保证事务提交在锁释放之前
  • 采用 aop 方式,且aop优先级要高于spring 事务的增强,即 @order(N) N 要比 spring 事务增强器小

Aop 方式

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SimpleLock {

}

@Component
@Aspect
@Order(1) //优先级越低,先执行,最后退出,保证优先级在事务切面之前
public class AopAspect {

    @Around(value = "@annotation(simpleLock)")
    public Object around(ProceedingJoinPoint pjp, SimpleLock simpleLock) throws Throwable {
        System.out.println("get lock");
        try{
            return pjp.proceed();
        }finally {
            System.out.println("release lock");
        }
    }

}

请求 /trx/aop, 结果:

get lock
do order...
execute finally
orderEvent: temp
release lock

现在就正常了

再探索

debug 类: AbstractAdvisorAutoProxyCreator

在这里插入图片描述

可以发现 ,如果自定义Aspect ,没有指定 order 的话,order=Integer.MAX,并且执行顺序在事务增强器之后

当我们指定切面 order=1 时:

在这里插入图片描述

望谨记!!

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值