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);
        }
  • 相关阅读:
    解析ASP.NET Mvc开发之删除修改数据
    JavaScript module pattern精髓
    Remote验证及其改进(附源码)
    图模型的精确推理
    C#在泛型类中,通过表达式树构造lambda表达式
    类管理指针成员
    朴素贝页斯分类法
    使用Repository模式构建数据库访问层
    利用MVC的过滤器实现url的参数加密和解密
    在多线程中使用静态方法是否有线程安全问题
  • 原文地址:https://www.cnblogs.com/bchange/p/12742237.html
Copyright © 2011-2022 走看看