网站人多怎么优化,直接下载app到手机上,维拓设计在北京排名,同城约会软件哪个好优惠券秒杀一人一单 前言一、需求以及之前存在的问题二、增加一人一单逻辑1.初步代码2.封装一人一单逻辑3.控制锁的粒度 三、事务控制问题四、总结 前言
跟随黑马虎哥学习redis#xff1a;
这是我认为b站上最好的redis教程#xff0c;各方面讲解透彻#xff0c;知识点覆盖… 优惠券秒杀一人一单 前言一、需求以及之前存在的问题二、增加一人一单逻辑1.初步代码2.封装一人一单逻辑3.控制锁的粒度 三、事务控制问题四、总结 前言
跟随黑马虎哥学习redis
这是我认为b站上最好的redis教程各方面讲解透彻知识点覆盖比较全。 黑马redis视频链接B站黑马redis教学视频 本文参考黑马redis课程笔记。 一、需求以及之前存在的问题
需求修改秒杀业务要求同一个优惠券一个用户只能下一单。
之前的问题 优惠卷是为了引流但是目前的情况是一个人可以无限制的抢这个优惠卷所以我们应当增加一层逻辑让一个用户只能下一个单而不是让一个用户下多个单。
具体操作逻辑如下比如时间是否充足如果时间充足则进一步判断库存是否足够然后再根据优惠卷id和用户id查询是否已经下过这个订单如果下过这个订单则不再下单否则进行下单。
二、增加一人一单逻辑
实现流程
1.初步代码
Override
public Result seckillVoucher(Long voucherId) {// 1.查询优惠券SeckillVoucher voucher seckillVoucherService.getById(voucherId);// 2.判断秒杀是否开始if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {// 尚未开始return Result.fail(秒杀尚未开始);}// 3.判断秒杀是否已经结束if (voucher.getEndTime().isBefore(LocalDateTime.now())) {// 尚未开始return Result.fail(秒杀已经结束);}// 4.判断库存是否充足if (voucher.getStock() 1) {// 库存不足return Result.fail(库存不足);}// 5.一人一单逻辑// 5.1.用户idLong userId UserHolder.getUser().getId();int count query().eq(user_id, userId).eq(voucher_id, voucherId).count();// 5.2.判断是否存在if (count 0) {// 用户已经购买过了return Result.fail(用户已经购买过一次);}//6扣减库存boolean success seckillVoucherService.update().setSql(stock stock -1).eq(voucher_id, voucherId).update();if (!success) {//扣减库存return Result.fail(库存不足);}//7.创建订单VoucherOrder voucherOrder new VoucherOrder();// 7.1.订单idlong orderId redisIdWorker.nextId(order);voucherOrder.setId(orderId);voucherOrder.setUserId(userId);// 7.3.代金券idvoucherOrder.setVoucherId(voucherId);save(voucherOrder);return Result.ok(orderId);}存在问题 现在的问题还是和之前一样并发过来查询数据库都不存在订单所以我们还是需要加锁但是乐观锁比较适合更新数据而现在是插入数据所以我们需要使用悲观锁操作
注意 在这里提到了非常多的问题我们需要慢慢的来思考首先我们的初始方案是封装了一个createVoucherOrder方法同时为了确保他线程安全在方法上添加了一把synchronized 锁
2.封装一人一单逻辑
Transactional
public synchronized Result createVoucherOrder(Long voucherId) {Long userId UserHolder.getUser().getId();// 5.1.查询订单int count query().eq(user_id, userId).eq(voucher_id, voucherId).count();// 5.2.判断是否存在if (count 0) {// 用户已经购买过了return Result.fail(用户已经购买过一次);}// 6.扣减库存boolean success seckillVoucherService.update().setSql(stock stock - 1) // set stock stock - 1.eq(voucher_id, voucherId).gt(stock, 0) // where id ? and stock 0.update();if (!success) {// 扣减失败return Result.fail(库存不足);}// 7.创建订单VoucherOrder voucherOrder new VoucherOrder();// 7.1.订单idlong orderId redisIdWorker.nextId(order);voucherOrder.setId(orderId);// 7.2.用户idvoucherOrder.setUserId(userId);// 7.3.代金券idvoucherOrder.setVoucherId(voucherId);save(voucherOrder);// 7.返回订单idreturn Result.ok(orderId);
}此时面临的问题 这样添加锁锁的粒度太粗了在使用锁过程中控制锁粒度 是一个非常重要的事情因为如果锁的粒度太大会导致每个线程进来都会锁住。
3.控制锁的粒度
intern() 这个方法是从常量池中拿到数据如果我们直接使用userId.toString() 他拿到的对象实际上是不同的对象new出来的对象我们使用锁必须保证锁必须是同一把所以我们需要使用intern()方法
Transactional
public Result createVoucherOrder(Long voucherId) {Long userId UserHolder.getUser().getId();synchronized(userId.toString().intern()){// 5.1.查询订单int count query().eq(user_id, userId).eq(voucher_id, voucherId).count();// 5.2.判断是否存在if (count 0) {// 用户已经购买过了return Result.fail(用户已经购买过一次);}// 6.扣减库存boolean success seckillVoucherService.update().setSql(stock stock - 1) // set stock stock - 1.eq(voucher_id, voucherId).gt(stock, 0) // where id ? and stock 0.update();if (!success) {// 扣减失败return Result.fail(库存不足);}// 7.创建订单VoucherOrder voucherOrder new VoucherOrder();// 7.1.订单idlong orderId redisIdWorker.nextId(order);voucherOrder.setId(orderId);// 7.2.用户idvoucherOrder.setUserId(userId);// 7.3.代金券idvoucherOrder.setVoucherId(voucherId);save(voucherOrder);// 7.返回订单idreturn Result.ok(orderId);}
}三、事务控制问题
以上代码还是存在问题问题的原因在于当前方法被spring的事务控制如果你在方法内部加锁可能会导致当前方法事务还没有提交但是锁已经释放也会导致问题所以我们选择将当前方法整体包裹起来确保事务不会出现问题 但是以上做法依然有问题因为你调用的方法其实是this.的方式调用的事务想要生效还得利用代理来生效所以这个地方我们需要获得原始的事务对象 来操作事务
Long userId UserHolder.getUser().getId();//创建锁对象SimpleRedisLock simpleRedisLock new SimpleRedisLock(order userId, stringRedisTemplate);//获取锁boolean isLock simpleRedisLock.tryLock(1200);if (!isLock) {//获取锁失败返回错误信息或重试return Result.fail(不允许重复下单);}try {//增加代理对象进行事务的控制IVoucherOrderService proxy (IVoucherOrderService) AopContext.currentProxy();return proxy.createVoucherOrder(voucherId);}finally {simpleRedisLock.unlock();}四、总结
这只是一人一单单机实现的方法因为synchronized锁只能确保在一个jvm中实现锁的互斥如果在集群中有多个jvm那就不能实现互斥锁最终还是会导致并发问题这个问题的解决由集群中的分布式锁解决。 文章转载自: http://www.morning.yrrnx.cn.gov.cn.yrrnx.cn http://www.morning.gnbfj.cn.gov.cn.gnbfj.cn http://www.morning.wrdlf.cn.gov.cn.wrdlf.cn http://www.morning.bpp999.com.gov.cn.bpp999.com http://www.morning.srcth.cn.gov.cn.srcth.cn http://www.morning.dwkfx.cn.gov.cn.dwkfx.cn http://www.morning.qkxnw.cn.gov.cn.qkxnw.cn http://www.morning.mhmdx.cn.gov.cn.mhmdx.cn http://www.morning.hmgqy.cn.gov.cn.hmgqy.cn http://www.morning.lsssx.cn.gov.cn.lsssx.cn http://www.morning.ssqwr.cn.gov.cn.ssqwr.cn http://www.morning.yxnfd.cn.gov.cn.yxnfd.cn http://www.morning.nfpgc.cn.gov.cn.nfpgc.cn http://www.morning.bnrnb.cn.gov.cn.bnrnb.cn http://www.morning.xuejitest.com.gov.cn.xuejitest.com http://www.morning.xkzmz.cn.gov.cn.xkzmz.cn http://www.morning.wlnr.cn.gov.cn.wlnr.cn http://www.morning.rnpnn.cn.gov.cn.rnpnn.cn http://www.morning.xhxsr.cn.gov.cn.xhxsr.cn http://www.morning.zthln.cn.gov.cn.zthln.cn http://www.morning.tbbxn.cn.gov.cn.tbbxn.cn http://www.morning.sqqds.cn.gov.cn.sqqds.cn http://www.morning.ylph.cn.gov.cn.ylph.cn http://www.morning.gthgf.cn.gov.cn.gthgf.cn http://www.morning.bzkgn.cn.gov.cn.bzkgn.cn http://www.morning.tpnch.cn.gov.cn.tpnch.cn http://www.morning.nlpbh.cn.gov.cn.nlpbh.cn http://www.morning.lwdzt.cn.gov.cn.lwdzt.cn http://www.morning.fkmqg.cn.gov.cn.fkmqg.cn http://www.morning.qwmpn.cn.gov.cn.qwmpn.cn http://www.morning.hnrls.cn.gov.cn.hnrls.cn http://www.morning.ljjmr.cn.gov.cn.ljjmr.cn http://www.morning.pdmsj.cn.gov.cn.pdmsj.cn http://www.morning.ykrkb.cn.gov.cn.ykrkb.cn http://www.morning.cqwb25.cn.gov.cn.cqwb25.cn http://www.morning.nflpk.cn.gov.cn.nflpk.cn http://www.morning.gbjxj.cn.gov.cn.gbjxj.cn http://www.morning.qljxm.cn.gov.cn.qljxm.cn http://www.morning.dtrz.cn.gov.cn.dtrz.cn http://www.morning.mtbth.cn.gov.cn.mtbth.cn http://www.morning.fwlch.cn.gov.cn.fwlch.cn http://www.morning.hgtr.cn.gov.cn.hgtr.cn http://www.morning.ctrkh.cn.gov.cn.ctrkh.cn http://www.morning.txrkq.cn.gov.cn.txrkq.cn http://www.morning.dcdhj.cn.gov.cn.dcdhj.cn http://www.morning.rsdm.cn.gov.cn.rsdm.cn http://www.morning.iiunion.com.gov.cn.iiunion.com http://www.morning.cznsq.cn.gov.cn.cznsq.cn http://www.morning.jfwbr.cn.gov.cn.jfwbr.cn http://www.morning.ckwxs.cn.gov.cn.ckwxs.cn http://www.morning.khxyx.cn.gov.cn.khxyx.cn http://www.morning.lzttq.cn.gov.cn.lzttq.cn http://www.morning.nclbk.cn.gov.cn.nclbk.cn http://www.morning.xdjsx.cn.gov.cn.xdjsx.cn http://www.morning.cmzgt.cn.gov.cn.cmzgt.cn http://www.morning.rykmf.cn.gov.cn.rykmf.cn http://www.morning.glcgy.cn.gov.cn.glcgy.cn http://www.morning.zqkr.cn.gov.cn.zqkr.cn http://www.morning.crsqs.cn.gov.cn.crsqs.cn http://www.morning.hcxhz.cn.gov.cn.hcxhz.cn http://www.morning.brlgf.cn.gov.cn.brlgf.cn http://www.morning.hbfqm.cn.gov.cn.hbfqm.cn http://www.morning.qrmry.cn.gov.cn.qrmry.cn http://www.morning.dhxnr.cn.gov.cn.dhxnr.cn http://www.morning.kjdxh.cn.gov.cn.kjdxh.cn http://www.morning.njftk.cn.gov.cn.njftk.cn http://www.morning.xxsrm.cn.gov.cn.xxsrm.cn http://www.morning.rfxg.cn.gov.cn.rfxg.cn http://www.morning.tqsmc.cn.gov.cn.tqsmc.cn http://www.morning.tzzxs.cn.gov.cn.tzzxs.cn http://www.morning.nmpdm.cn.gov.cn.nmpdm.cn http://www.morning.qypjk.cn.gov.cn.qypjk.cn http://www.morning.nytgk.cn.gov.cn.nytgk.cn http://www.morning.dhqyh.cn.gov.cn.dhqyh.cn http://www.morning.fxkgp.cn.gov.cn.fxkgp.cn http://www.morning.wknbc.cn.gov.cn.wknbc.cn http://www.morning.mbmtz.cn.gov.cn.mbmtz.cn http://www.morning.rfyk.cn.gov.cn.rfyk.cn http://www.morning.tfzjl.cn.gov.cn.tfzjl.cn http://www.morning.lysrt.cn.gov.cn.lysrt.cn