二话不说,直接上货.多多交流哈,谢谢各路大神.
.
重点就是下面这段:
Object object = redisTemplate.execute(redisUpdateOrderScript, //这里有key 要像官网说的那样加个"{}",不然就报错了,这里3个key都要前缀一致 Arrays.asList(hkey, amountKey, key), //值无要求 amount.longValueExact(),price.doubleValue(),price.doubleValue());
我自己的理解是,执行脚本和执行hget 是一样的,只是lua脚本内容由Redis执行,但发送命令的要求是一样的.所以上面3个key 都得加一样的前缀.
.
.
.
业务逻辑是这样子的:
把20档盘口放到Redis里面
1.用有序集合(sorted set)进行自动价格排序
ZADD key 0.0354 "0.0354"
2.然后再根据价格到hash里去取值,取的val 就是这个价格的下单量
HGET key 0.0354
java 代码
加盘口
public void addOrderForLua(BeforeMatchDTO model) { //缓存失效 redisService.remove(RedisService.getPositionKey(model.getContract())); BigDecimal price = model.getPrice(); BigDecimal amount = model.getAmount().multiply(PRECISION_DOUBLE); String key = RedisKeyGen.getContractPositionZsetKey(model.getContract(), model.getDirection()); log.info("getContractPositionZsetKey:{}",key); String hkey = RedisKeyGen.getContractPositionHashKey(model.getContract(), model.getDirection()); log.info("getContractPositionHashKey:{}",hkey); String amountKey = RedisKeyGen.getContractPositionAmountKey(model.getContract(),price.stripTrailingZeros().toPlainString()); log.info("getContractPositionAmountKey:{}",amountKey); log.info("addOrderForLua contract:{}, value:{}", model.getContract(), amount.longValueExact()); Object object = redisTemplate.execute(redisUpdateOrderScript, Arrays.asList(hkey, amountKey, key), amount.longValueExact(),price.doubleValue(),price.doubleValue()); log.info("addOrderForLua" + object); }
减盘口
public void subOrderForLua(String contract,BigDecimal price,BigDecimal amount,int direction) { //缓存失效 redisService.remove(RedisService.getPositionKey(contract)); String key = RedisKeyGen.getContractPositionZsetKey(contract, direction); log.info("getContractPositionZsetKey:{}",key); String hkey = RedisKeyGen.getContractPositionHashKey(contract, direction); log.info("getContractPositionHashKey:{}",hkey); String amountKey = RedisKeyGen.getContractPositionAmountKey(contract,price.stripTrailingZeros().toPlainString()); log.info("getContractPositionAmountKey:{}",amountKey); log.info("subOrderForLua contract:{}, value:{}", contract, amount.doubleValue()); BigDecimal amountTag = amount.multiply(PRECISION_DOUBLE).negate(); //转成负数 Object nowAmount = redisService.hmGet(hkey, price.toPlainString()); log.info("subOrderForLua nowAmount:{},direction:{}", nowAmount, direction); Object object = redisTemplate.execute(redisUpdateOrderScript, Arrays.asList(hkey, amountKey, key), amountTag.longValueExact(),price.doubleValue(),price.doubleValue()); log.info("subOrderForLua" + object); }
查询(重点看取值的地方,转换请忽略)
public List<QuotationOrderRsgResp> query(String contract,int direction) { List<QuotationOrderRsgResp> result = new ArrayList<>(); String key = RedisKeyGen.getContractPositionZsetKey(contract, direction); log.info("getContractPositionZsetKey:{}",key); String hkey = RedisKeyGen.getContractPositionHashKey(contract, direction); log.info("getContractPositionHashKey:{}",hkey); Set<Object> objectSet = null; //卖从低到高 if(QuotationConstants.DIRECTION_SELL == direction) { objectSet = redisService.rangeByIndex(key, 0, 19); } else { //买从高到低 objectSet = redisService.reverseRangeByIndex(key, 0, 19); } if (objectSet != null && objectSet.size() > 0) { Integer [] digits = convertService.getContractDigitsForInt(contract); for (Object obj : objectSet) { log.info("query class:{},val:{}",obj.getClass(),JSON.toJSONString(obj)); BigDecimal price = new BigDecimal(obj.toString()); String amountKey = RedisKeyGen.getContractPositionAmountKey(contract,price.stripTrailingZeros().toPlainString()); Object object = redisService.hmGet(hkey, amountKey); log.info("getContractPositionAmountKey hmGet key:{},val:{}",amountKey,object); BigDecimal valTemp = getBigDecimal(object); if(valTemp.compareTo(BigDecimal.ZERO) == 0) continue; BigDecimal val = valTemp.divide(PRECISION_DOUBLE); QuotationOrderRsgResp resp = new QuotationOrderRsgResp(); resp.setContract(contract); resp.setDirection(direction); resp.setPrice(convertService.setScale(price, digits[0])); resp.setVolume(convertService.setScale(val,digits[1])); resp.setTotal(convertService.setScale(price.multiply(val),add(digits[0] ,digits[1]))); result.add(resp); } } else { log.info("query redis is null! contract:{},direction:{}", contract, direction); } return result; }
key 生成
public static final String getContractPositionZsetKey(String contract,int direction){ return "{POSITION:"+contract+"}.POSITION-ORDER-" + contract + "-" + direction; } public static final String getContractPositionHashKey(String contract,int direction){ return "{POSITION:"+contract+"}.POSITION-ORDER-VAL-" + contract + "-" + direction; } public static final String getContractPositionAmountKey(String contract,String amount){ return "{POSITION:"+contract+"}." + amount; }
lua 脚本
local val1 = '"' local valAmount = redis.call('hget',KEYS[1],KEYS[2]) if not valAmount then redis.pcall('hset',KEYS[1],KEYS[2],ARGV[1]) if tonumber(ARGV[1]) > 0 then local val2 = val1 .. ARGV[3] .. val1 return redis.pcall('ZADD', KEYS[3], tonumber(ARGV[2]), val2) else return 1 end else local tagAmount = tonumber(valAmount) + ARGV[1] redis.pcall('hset',KEYS[1],KEYS[2],tagAmount) local val2 = val1 .. ARGV[3] .. val1 local zset = redis.pcall('ZRANK', KEYS[3], val2) if tagAmount <= 0 then if not zset then return 1 else return redis.pcall('ZREMRANGEBYSCORE', KEYS[3], tonumber(ARGV[2]), tonumber(ARGV[2])) end else if not zset then local val2 = val1 .. ARGV[3] .. val1 return redis.pcall('ZADD', KEYS[3], tonumber(ARGV[2]), val2) else return 1 end end end