中国联通网站备案,wordpress wp loginpro,游戏优化大师手机版,有哪些网站可以做店面设计1、目的 使用lua脚本#xff0c;可以保证多条命令的操作原子性#xff1b;同时可以减少操作IO#xff08;比如说判断redis对应数据是否小于0#xff0c;小于0就重置为100#xff0c;这个场景一般是取出来再判断#xff0c;再存放进行#xff0c;就至少存在2次IO,用lua脚…1、目的 使用lua脚本可以保证多条命令的操作原子性同时可以减少操作IO比如说判断redis对应数据是否小于0小于0就重置为100这个场景一般是取出来再判断再存放进行就至少存在2次IO,用lua脚本一条命令1次IO就解决了,在批量扣减情况存在多次IOlua脚本1次也可以解决提高速度降低IO. 2、使用案列 根据传入的产品标识及数量扣减该产品数量此处为单个产品扣减可优化为批量产品传入lua内部用table处理。
2.1 初始化redis参数
添加产品及库存hash结构。添加两种水果的库存。
// 向Redis中添加数据
redisTemplate.opsForHash().put(productMap, pro1, {\name\:\苹果\,\stock\:100});
redisTemplate.opsForHash().put(productMap, pro2, {\name\:\西瓜\,\stock\:1200});
查看结果 2.2 业务代码
传入lua脚本实现对应产品库存数量扣减。(可优化为多产品批量扣减)
通过setnx加锁防止死锁设置锁超时时间同时业务执行完手动释放锁。设置锁等待时间、及锁等待轮询获取锁。(eg自旋释放cpu资源重新抢占资源)
Test
public void tete(){// 向Redis中添加数据redisTemplate.opsForHash().put(productMap, pro1, {\name\:\苹果\,\stock\:100});redisTemplate.opsForHash().put(productMap, pro2, {\name\:\西瓜\,\stock\:1200});// Lua 脚本字符串 String luaScript local productKey KEYS[1]; local pro KEYS[2]; local lockKey KEYS[3]; local lockTimeout tonumber(ARGV[1]); local deductAmount tonumber(ARGV[2]); local spinIntervalMs tonumber(ARGV[3]); local maxSpinCount tonumber(ARGV[4]); local lockAcquired redis.call(setnx, lockKey, 1); if lockAcquired 1 then redis.call(pexpire, lockKey, lockTimeout); local currentValue redis.call(hget, productKey, pro); if currentValue then local dbObj cjson.decode(currentValue); local currentStock tonumber(dbObj.stock); if currentStock deductAmount then dbObj.stock currentStock - deductAmount; local updatedValue cjson.encode(dbObj); redis.call(hset, productKey, pro, updatedValue); redis.call(del, lockKey); // 释放锁 return true; else return false; end else return false; end else local spinCount 0; while spinCount maxSpinCount do local lockValue redis.call(get, lockKey); if not lockValue then lockAcquired redis.call(setnx, lockKey, 1); if lockAcquired 1 then redis.call(pexpire, lockKey, lockTimeout); local currentValue redis.call(hget, productKey, pro); if currentValue then local dbObj cjson.decode(currentValue); local currentStock tonumber(dbObj.stock); if currentStock deductAmount then dbObj.stock currentStock - deductAmount; local updatedValue cjson.encode(dbObj); redis.call(hset, productKey, pro, updatedValue); redis.call(del, lockKey); return true; else return false; end else return false; end end break; end spinCount spinCount 1; end return false; end;// 创建DefaultRedisScript对象DefaultRedisScriptBoolean script new DefaultRedisScript();script.setScriptText(luaScript);script.setResultType(Boolean.class); // 设置返回类型为Boolean// 执行脚本Boolean result (Boolean) redisTemplate.execute(script,Collections.unmodifiableList(List.of(productMap,pro1,lock:pro1)), // KEYS参数50000, // ARGV参数第一个锁过期时间毫秒10, // ARGV参数第二个扣减数量1000,// ARGV参数第3个等待时间5);// ARGV参数第4个轮询次数System.out.println(result1:result);Boolean result2 (Boolean) redisTemplate.execute(script,Collections.unmodifiableList(List.of(productMap,pro1,lock:pro1)), // KEYS参数50000, // ARGV参数第一个锁过期时间毫秒10, // ARGV参数第二个扣减数量1000,5);System.out.println(result2:result2);Boolean result3 (Boolean) redisTemplate.execute(script,Collections.unmodifiableList(List.of(productMap,pro1,lock:pro1)), // KEYS参数50000, // ARGV参数第一个锁过期时间毫秒10, // ARGV参数第二个扣减数量1000,5);System.out.println(result3:result3);if (result2) {System.out.println(Stock deduction successful.);} else {System.out.println(Insufficient stock or lock already acquired.);}// 验证库存是否正确扣减Object updatedValue redisTemplate.opsForHash().get(productMap, pro1);System.out.println(updatedValue);Boolean result5 (Boolean) redisTemplate.execute(script,Collections.unmodifiableList(List.of(productMap,pro2,lock:pro2)), // KEYS参数5000, // ARGV参数第一个锁过期时间毫秒500, // ARGV参数第二个扣减数量1000,5);
} 2.3 正常执行结果 2.4 若获取锁超时则会出现扣减失败
脚本执行时间过长会导致。此处可通过删除手动释放锁实现模拟业务耗时过长没办法手动释放锁需等待锁国企时间
第二个扣减等待超时。可通过设置调整添加自旋时间重试或业务代码判断重试机制