zoukankan      html  css  js  c++  java
  • springbot单机秒杀,锁与事务之间的大坑

    一:

    先上结论,如果把锁放在事务里面,会出现脏读数据,解决方案:锁上移。

    1.有问题的代码:

    @Service
    public class SeckillServiceImpl extends ServiceImpl<SeckillMapper, Seckill> implements ISeckillService {
    
        private static Lock lock = new ReentrantLock(true);
    
        @Autowired
        private ISuccessKilledService successKilledService;
    
        @Override
        @Transactional
        public String startKill(String id) {
    
            lock.lock();
            try {
                Seckill seckill = this.getOne(new LambdaQueryWrapper<Seckill>().eq(Seckill::getSeckillId, id));
                int number = seckill.getNumber();
                if (number > 0) {
    
                    Seckill seckill1 = seckill.setNumber(--number);
                    this.update(seckill1, new LambdaQueryWrapper<Seckill>().eq(Seckill::getSeckillId, seckill.getSeckillId()));
    
                    SuccessKilled successKilled = new SuccessKilled();
                    successKilled.setUserId(1L);
                    successKilled.setSeckillId(seckill.getSeckillId());
                    successKilled.setState(0);
                    successKilled.setCreateTime(new Date());
                    successKilledService.save(successKilled);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            return "success";
        }
    }

    本例子中锁在事务里面,并发时就会出现锁已经解锁了单事务没有提交,另一个线程读到了没有 提交之前的数据。

    解决方案:

    AOP+锁。

    @Target({ElementType.PARAMETER, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Servicelock {
        String description() default "";
    }
    @Component
    @Aspect
    public class LockAspect {
        private static Lock lock = new ReentrantLock(true);//互斥锁 参数默认false,不公平锁
    
        @Pointcut("@annotation(com.example.demo.Servicelock)")
        public void lockAspect() {
    
        }
    
        @Around("lockAspect()")
        public Object around(ProceedingJoinPoint joinPoint) {
            lock.lock();
            Object obj = null;
            try {
                obj = joinPoint.proceed();
            } catch (Throwable e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            return obj;
        }
    }

    注意:通知类型一定要是环绕通知。

     @RequestMapping("start")
        @ResponseBody
        @Servicelock
        public String start(String seckillId) {
    
            return killService.startKill(seckillId);
        }
  • 相关阅读:
    android选择时间攻略
    安卓通知的基本用法
    个人作业----软件工程实践总结
    第三次作业——《K米评测》
    第二次结对编程作业——毕设导师智能匹配
    原型设计与需求分析
    作品调研
    软件工程的实践项目课程的自我目标
    软件工程实践总结作业20161231
    K米测试
  • 原文地址:https://www.cnblogs.com/bchange/p/12742237.html
Copyright © 2011-2022 走看看