redis实现 msetex和 getdel命令
1.redis本身不提供 msetex命令(批量增加key并设置过期时间)
class RedisExtend { private static final Logger logger = LoggerFactory.getLogger(RedisExtend.class); private static final int Port = 6379; private static final String Host = "192.168.1.1"; private static final String PASS_WORD = "1234"; private static Jedis instance; /** * Lua脚本(msetex) */ private static final String LUA_SCRIPT_MSETEX = "local keysLen = table.getn(KEYS);" + "local argvLen = table.getn(ARGV);" + "local idx=1;" + "local argVIdx=1;" + "for idx=1,keysLen,1 do " + "argVIdx=(idx-1)*2+1; " + "redis.call('Set',KEYS[idx],ARGV[argVIdx],'EX',ARGV[argVIdx+1]);" + "end " + "return keysLen;"; private static String LUA_SCRIPT_MSETEX_SHA1; /** * Lua脚本 (获取后删除) */ private static final String LUA_SCRIPT_GET_AND_DELETE = "local current = redis.call('get', KEYS[1]);\n" + "if (current) then\n" + " redis.call('del', KEYS[1]);\n" + "end\n" + "return current;"; private static String LUA_SCRIPT_GET_AND_DELETE_SHA1; static { LUA_SCRIPT_MSETEX_SHA1 = SHA1.encode(LUA_SCRIPT_MSETEX); LUA_SCRIPT_GET_AND_DELETE_SHA1 = SHA1.encode(LUA_SCRIPT_GET_AND_DELETE); } public static Jedis getInstance() { if (instance == null) { instance = initJedisLite().getTemplate().getJedisPool().getResource(); } return instance; } private static JedisLite initJedisLite() { return new JedisLite(Host, Port); } private static JedisTemplate jedisTemplate = initJedisLite().getTemplate(); public static long msetex(List<RedisKeyValue> redisKeyValues) { if (CollectionUtils.isEmpty(redisKeyValues)) { return 0; } int keyCount = redisKeyValues.size(); List<String> param = new ArrayList<>(keyCount * 3); for (RedisKeyValue item : redisKeyValues) { Assert.notNull(item, "KeyValue不允许为空"); Assert.hasLength(item.getKey(), "Key不允许为空"); param.add(item.getKey()); } for (RedisKeyValue item : redisKeyValues) { param.add(item.getValue()); param.add(Integer.toString(item.getSeconds())); } String[] paramArr = new String[param.size()]; param.toArray(paramArr); return execLunaScript(new RedisScript(LUA_SCRIPT_MSETEX, LUA_SCRIPT_MSETEX_SHA1), keyCount, paramArr, (o) -> (long) (o == null ? 0L : Integer.parseInt(o.toString()))); } public static String getdel(String key) { return execLunaScript(new RedisScript(LUA_SCRIPT_GET_AND_DELETE, LUA_SCRIPT_GET_AND_DELETE_SHA1), 1, new String[]{key}, (o) -> (o == null ? null : o.toString())); } private static <T> T execLunaScript(RedisScript redisScriptObj, int keyCount, String[] param, Function<Object, T> function) { try { return jedisTemplate.execute((Jedis jedis) -> function.apply(jedis.evalsha(redisScriptObj.sha1, keyCount, param))); } catch (redis.clients.jedis.exceptions.JedisNoScriptException ex) { return jedisTemplate.execute((Jedis jedis) -> function.apply(jedis.eval(redisScriptObj.script, keyCount, param))); } catch (Exception ex) { logger.error("执行redis脚本异常!", ex); return null; } } static class RedisScript { private String script; private String sha1; public RedisScript(String script) { this(script, SHA1.encode(script)); } public RedisScript(String script, String sha1) { this.script = script; this.sha1 = sha1; } } static class RedisKeyValue { private String key; private String value; private int seconds; public RedisKeyValue(String key, String value) { this(key, value, -1); } public RedisKeyValue(String key, String value, int seconds) { this.key = key; this.value = value; this.seconds = seconds; } public String getKey() { return key; } public String getValue() { return value; } public int getSeconds() { return seconds; } } }
2.调用代码如下
public static void main(String[] args) { long r = msetex( Arrays.asList(new RedisKeyValue("key1", "value1", 5000), new RedisKeyValue("key2", "value2", 5000), new RedisKeyValue("ke3", "value3", 5000) )); System.out.println("返回值:" + r); String key1Val = getdel("key1"); System.out.println("key1的值:" + key1Val); key1Val = getdel("key1"); System.out.println("key1的值:" + key1Val); }
3.返回结果如下
返回值:3 key1的值:value1 key1的值:null
4.sha1的代码如下
import java.security.MessageDigest; public class SHA1 { private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; /** * Takes the raw bytes from the digest and formats them correct. * * @param bytes the raw bytes from the digest. * @return the formatted bytes. */ private static String getFormattedText(byte[] bytes) { int len = bytes.length; StringBuilder buf = new StringBuilder(len * 2); // 把密文转换成十六进制的字符串形式 for (int j = 0; j < len; j++) { buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]); buf.append(HEX_DIGITS[bytes[j] & 0x0f]); } return buf.toString(); } public static String encode(String str) { if (str == null) { return null; } try { MessageDigest messageDigest = MessageDigest.getInstance("SHA1"); messageDigest.update(str.getBytes()); return getFormattedText(messageDigest.digest()); } catch (Exception e) { throw new RuntimeException(e); } } }