该栏目会系统的介绍 Redis 的知识体系,共分为相关概念、操作指令、主从复制等模块
功能 | 指令 |
---|---|
组队 | multi |
执行 | exec |
取消组队 | discard |
监视 | watch |
取消监视 | unwatch |
/** * 1、使用连接池解决超时问题 * 2、使用事务与乐观锁解决超卖问题,但引入遗留库存问题,用Lua脚本解决 * * @param productId 商品Id * @param userId 用户Id * @return 操作结果 */ @Test public boolean secKill(String productId, String userId) { if (productId == null || userId == null) { return false; } // 定义key String stockKey = "sk:" + productId + ":stock"; String userKey = "sk:" + productId + ":user"; // 判断秒杀是否开始 final String stock = (String) stringOps.get(stockKey); if (stock == null) { System.out.println("秒杀活动还没开始,请等待"); return false; } // 判断用户是否已经秒杀过 final Boolean result = Optional.ofNullable(setOps.isMember(userKey, userId)).get(); if (result) { System.out.println("用户已经参加过秒杀了"); return false; } // 判断秒杀是否结束 if (Integer.parseInt(stock) <= 0) { System.out.println("秒杀结束..."); return false; } // 监视库存,使用乐观锁机制 redisTemplate.watch(stockKey); // 开启事务 redisTemplate.multi(); stringOps.decrement(stockKey); setOps.add(userKey, userId); final List<Object> results = redisTemplate.exec(); if (results.size() == 0) { System.out.println("秒杀失败"); return false; } System.out.println("秒杀成功"); return true; } /** * LUA脚本概述:将复杂的或者多步的redis操作,写为一个脚本,一次提交给redis执行,减少反复连接 * redis的次数。提升性能。LUA脚本是类似redis事务,有一定的原子性,不会被其他命令插队,可以完 * 成一些redis事务性的操作 * * 使用Lua脚本解决遗留库存问题 * * @param productId 商品Id * @param userId 用户Id * @return 操作结果 */ @Test public boolean secKillScript(String productId, String userId) { String secKillScript = "local userid=KEYS[1];\r\n" + "local prodid=KEYS[2];\r\n" + "local qtkey='sk:'..prodid..\":qt\";\r\n" + "local usersKey='sk:'..prodid..\":usr\";\r\n" + "local userExists=redis.call(\"sismember\",usersKey,userid);\r\n" + "if tonumber(userExists)==1 then \r\n" + " return 2;\r\n" + "end\r\n" + "local num= redis.call(\"get\" ,qtkey);\r\n" + "if tonumber(num)<=0 then \r\n" + " return 0;\r\n" + "else \r\n" + " redis.call(\"decr\",qtkey);\r\n" + " redis.call(\"sadd\",usersKey,userid);\r\n" + "end\r\n" + "return 1"; // 定义key String stockKey = "sk:" + productId + ":stock"; String userKey = "sk:" + userId + ":user"; // 执行Lua脚本 DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(); redisScript.setScriptText(secKillScript); redisScript.setResultType(Long.class); final long result = Optional.ofNullable(redisTemplate.execute( redisScript, Arrays.asList(userId, productId))).get(); if (0 == result) { System.out.println("秒杀活动结束"); return false; } else if (1 == result) { System.out.println("秒杀成功"); return true; } else if (2 == result) { System.out.println("用户已经参加过秒杀了"); return false; } else { System.out.println("秒杀异常!"); return false; } }