秒杀业并发业务问题(单体)

单体系统一人一单并发问题总结

1.悲观锁

  • 添加同步锁,让线程串行化执行(性能一般)
  • synchronize、lock

2.乐观锁

  • 不加锁,在更新时判断是否有其他线程在修改
  • 性能好,但存在成功率低的问题
  • CAS自旋锁
  • 添加版本号(version)解决A-B-A问题 -----> 1A-2B-3C

知识点随记:
1.spring框架事务失效
2.aop代理对象
3.synchronized锁对象

问题分析

需求:只有同一用户访问才考虑并发问题

  1. synchronized如果直接加在方法上,锁住的是当前对象,等于所有人访问都会加锁
	@Transactional
    public synchronized Result createVoucherOrder(Long voucherId){
        //一人一单
        Long userId = UserHolder.getUser().getId();
           		....
        		....
        		....
      	  
      	  return Result.ok()
	}
  1. 改进一:缩小范围,对用户id进行加锁

问题:当执行到方法的最后一行代码时,synchronized锁就会释放,但是现在事务还未提交,如果现在其他线程进来还是会出现并发问题,因为事务没有提交,数据库就没有得到更新

	@Transactional
    public Result createVoucherOrder(Long voucherId) {
        //一人一单
        Long userId = UserHolder.getUser().getId();
        //这里将userId转string后每次都会是一个新的对象
        //调用intern方法后他取的是string后的值进行比较
        synchronized (userId.toString().intern()) {
        		....
        		....
        		....
      	  }
      	  return Result.ok()
        }
  1. 改进二:放方法调用前加锁,实现事务先提交,再释放锁

问题:这里调用createVoucherOrder方法的对象是当前对象
1)事务生效:是因为spring对当前类进行了动态代理,使用代理对象对事务进行处理
2)这里的this是目标对象,属于非代理对象,所有这里是没有事务功能的,@Transactional会失效

	@Override
    public Result secKillVoucher(Long voucherId) {
	 			...
	 			...
	 			...
		Long userId = UserHolder.getUser().getId();
		//2.再释放锁
		synchronized (userId.toString().intern()) {
			//1.先提交事务
            return this.createVoucherOrder(voucherId);
        }
	}
	@Transactional
    public Result createVoucherOrder(Long voucherId) {
        //一人一单
        Long userId = UserHolder.getUser().getId();
        		....
        		....
        		....
      	  
      	  return Result.ok()
        }

解决事务失效问题

  1. 我们需要拿到代理对象
  2. 用代理对象去调用方法
  3. 记得加aspectjweaver依赖
  4. 记得在启动类开启AOP自动代理并暴露 EnableAspectJAutoProxy(exposeProxy = true)
  5. 完美解决
<dependency>
     <groupId>org.aspectj</groupId>
     <artifactId>aspectjweaver</artifactId>
</dependency>
	@Override
    public Result secKillVoucher(Long voucherId) {
	 			...
	 			...
	 			...
		Long userId = UserHolder.getUser().getId();
		//2.再释放锁
		synchronized (userId.toString().intern()) {
			//1.先提交事务
            //获取当前对象的代理对象
            IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
            //proxy是由spring容器管理的,用proxy调用方法事务就会生效
            return proxy.createVoucherOrder(voucherId);
        }
	}
	@Transactional
    public Result createVoucherOrder(Long voucherId) {
        //一人一单
        Long userId = UserHolder.getUser().getId();
        		....
        		....
        		....
      	  
      	  return Result.ok()
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值