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);
        }
  • 相关阅读:
    Java正式day_06——数组排序
    别只知道策略模式+简单工厂,试试更香的策略模式+抽象工厂!
    图解连接阿里云(一)创建阿里云物联网平台产品和设备,使用MQTT.fx快速体验
    嵌入式交叉编译GDB,结合vscode图形化调试C和C++代码 coredump定位段错误
    内核链表之list_for_eacy_entry手绘图解
    makefile实验三 理解make工作的基本原则
    玩转Libmodbus(一) 搭建开发环境
    RT-Thread的C语言多态风格展示
    C++函数默认参数 详解
    杂类-边学边记
  • 原文地址:https://www.cnblogs.com/bchange/p/12742237.html
Copyright © 2011-2022 走看看