超卖就是因为查询库存和扣减库存两个操作不是原子性操作,通过rua脚本执行这两个操作可以保证这两个操作原子性
判断库存量是不是大于等于1,如果大于等于1对库存减1,否则就不去减库存
StringBuilder sb = new StringBuilder(); sb.append("if (redis.call('exists', KEYS[1]) == 1) then"); sb.append(" local stock = tonumber(redis.call('get', KEYS[1]));"); sb.append(" if (stock == -1) then"); sb.append(" return 1;"); sb.append(" end;"); sb.append(" if (stock > 0) then"); sb.append(" redis.call('incrby', KEYS[1], -1);"); sb.append(" return stock;"); sb.append(" end;"); sb.append(" return 0;"); sb.append("end;"); sb.append("return -1;");
为什么使用lua脚本可以实现原子性,不会产生并发问题呢?
redis虽然I/O模块是多线程,但是执行执行命令的时候是单线程的,而且支持多行模式,也就是一个lua脚本里的多行代码认为是一个单个任务,单个命令,前面的任务(命令)不执行完,后面的任务无法执行