java+redis+lua生成自动增长的ID序列号
1. 编写 lua 脚本用于生成主键 ID 序列号, 内容如下
local key = tostring(KEYS[1]);
local count = tonumber(KEYS[2]);
local dateStr = tostring(KEYS[3]);
local newKey = key .. "_" .. dateStr;
local numRedis = redis.call("incr", newKey);
print(numRedis);
if (numRedis == 1) then
redis.call("expire",newKey,60);
end
-- 计算数字的位数
local function DightNum(num)
if math.floor(num) ~= num or num < 0 then
return -1;
elseif 0 == num then
return 1;
else
local tmp_dight = 0;
while num > 0 do
num = math.floor(num/10);
tmp_dight = tmp_dight + 1;
end
return tmp_dight;
end
end
-- 在整数数字前面加 0
-- dest_dight 标识最终生成位数,例如 AddZeroFrontNum(5, 1) 计算后是 00001
local function AddZeroFrontNum(dest_dight, num)
local num_dight = DightNum(num);
if -1 == num_dight then
return -1;
elseif dest_dight <= num_dight then
return tostring(num);
else
local str_e = ""
for var =1, dest_dight - num_dight do
str_e = str_e .. "0";
end
return str_e .. tostring(num);
end
end
local idStr = AddZeroFrontNum(count, numRedis);
return dateStr .. idStr;
2.redis 加载 lua 脚本文件
redis-cli -a redis script load "$(cat getGenerateId.lua)"
"b3d58fe8b47b1ca1e1fb074db5c3506a09ffdae8"
-a: redis 密码,如果没有密码,该项不需要输入
下面的字符串即为加载后 redis 保存的 sha 值,通过该 sha 值可以访问 lua 脚本
3.java 代码执行缓存的 lua 脚本文件
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
@Service
public class RedisService {
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">DateFormat</span> <span class="hljs-variable">df</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SimpleDateFormat</span>(<span class="hljs-string">"yyyyMMddHHmmss"</span>);
<span class="hljs-meta">@Autowired</span>
<span class="hljs-keyword">private</span> RedisTemplate<String, String> redisTemplate;
<span class="hljs-keyword">public</span> Object <span class="hljs-title function_">executeScript</span><span class="hljs-params">(<span class="hljs-keyword">final</span> String sha, <span class="hljs-keyword">final</span> List<String> keys, <span class="hljs-keyword">final</span> ArrayList<String> vals)</span> {
<span class="hljs-keyword">return</span> redisTemplate.execute(<span class="hljs-keyword">new</span> <span class="hljs-title class_">RedisCallback</span>() {
<span class="hljs-meta">@Override</span>
<span class="hljs-keyword">public</span> Object <span class="hljs-title function_">doInRedis</span><span class="hljs-params">(RedisConnection connection)</span> <span class="hljs-keyword">throws</span> DataAccessException {
<span class="hljs-type">Jedis</span> <span class="hljs-variable">jedis</span> <span class="hljs-operator">=</span> (Jedis) connection.getNativeConnection();
<span class="hljs-keyword">return</span> jedis.evalsha(sha, keys, vals);
}
}, <span class="hljs-literal">true</span>);
}
<span class="hljs-comment">/**
* 每秒从 1 开始生成唯一标识,包括时间戳:yyyyMMddHHmmss
* 最终格式为:yyyyMMddHHmmss + 四位有序数字
* <span class="hljs-doctag">@param</span> sha redis中生成lua脚本的序列号
* <span class="hljs-doctag">@param</span> key redis中存放id的key前缀
* <span class="hljs-doctag">@param</span> length 后面生成有序数字的位数
* <span class="hljs-doctag">@return</span>
*/</span>
<span class="hljs-keyword">public</span> Long <span class="hljs-title function_">fetchUUID</span><span class="hljs-params">(String sha, String key, String length)</span>{
List<String> keys = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span><>();
keys.add(key);
keys.add(length);
<span class="hljs-type">Calendar</span> <span class="hljs-variable">now</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">GregorianCalendar</span>();
<span class="hljs-type">String</span> <span class="hljs-variable">datetime</span> <span class="hljs-operator">=</span> df.format(now.getTime());
keys.add(datetime);
<span class="hljs-type">Object</span> <span class="hljs-variable">obj</span> <span class="hljs-operator">=</span> executeScript(sha, keys, <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span><String>());
<span class="hljs-keyword">return</span> Long.parseLong(String.valueOf(obj));
}
}
然后调用 fetchUUID 该方法就可以了,key 和 length 自定义,sha 为第二步生成值