Redis Lua Java 随机编号 用户编号
Posted 伍有晓俐
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis Lua Java 随机编号 用户编号相关的知识,希望对你有一定的参考价值。
用户id主键递增的情况下,要为用户生产随机的用户编号,效果如下:
这是一种伪随机的方案,前缀随机,后面的编号递增
reids脚本
local prefix=0
local exists = redis.call('EXISTS', KEYS[1])
if exists == 1 then
-- 随机出set的一个前缀
prefix= redis.call('SRANDMEMBER', KEYS[1])
else
-- 初始化set KEYS[1] 默认1至9 10个前缀
for i=1, 9 do redis.call('SADD', KEYS[1],i) end
prefix = redis.call('SRANDMEMBER', KEYS[1])
end
-- 随机出set的前缀 对应的值递增
local currentNum = redis.call('hIncrBy', KEYS[2], prefix, ARGV[1])
if (currentNum > tonumber(ARGV[2])) then
-- 有进位 前缀值加9,对应的旧前缀从set移除,增加新前缀
local newPrefix = prefix + 9
local newCurrentNum = redis.call('hIncrBy', KEYS[2], newPrefix, ARGV[1])
redis.call('srem', KEYS[1], prefix)
redis.call('SADD', KEYS[1], newPrefix)
return (newPrefix * tonumber(ARGV[2])) + newCurrentNum
else
-- 无进位 直接返回
return (prefix * tonumber(ARGV[2])) + currentNum
end
前缀
前缀对应的自增后的值
Redis客户端测试
把脚本的注释去掉
redis:测试:1>eval "local prefix=0 local exists = redis.call('EXISTS', KEYS[1]) if exists == 1 then prefix= redis.call('SRANDMEMBER', KEYS[1]) else for i=1, 9 do redis.call('SADD', KEYS[1],i) end prefix = redis.call('SRANDMEMBER', KEYS[1]) end local currentNum = redis.call('hIncrBy', KEYS[2], prefix, ARGV[1]) if (currentNum > tonumber(ARGV[2])) then local newPrefix = prefix + 9 local newCurrentNum = redis.call('hIncrBy', KEYS[2], newPrefix, ARGV[1]) redis.call('srem', KEYS[1], prefix) redis.call('SADD', KEYS[1], newPrefix) return (newPrefix * tonumber(ARGV[2])) + newCurrentNum else return (prefix * tonumber(ARGV[2])) + currentNum end" 2 account_random_number_prefix_set account_random_number_hash 2332 10000
"13031"
redis测试:1>
Java 代码
/**
* 五位数最大值(不包含)
*/
private static final Long FIVE_DIGITS_MAX = 100000L;
/**
* 用户随机ID 前缀
* 首批前缀序号为
* 递增规则如下:
* 1 --10 --19 --28
* 2 --11 --20 --29
* 3
* 4
* 5
* 6
* 7
* 8
* 9 --18 --27 --36
* 并且位数超过当前最大值 递增9为新前缀序号
*/
String ACCOUNT_RANDOM_NUMBER_PREFIX_SET = "account_random_number_prefix_set";
/**
* 用户前缀下的自增number
*/
String ACCOUNT_RANDOM_NUMBER_HASH = "account_random_number_hash";
/**
* lua脚本生成用户随机编号
*/
public Long doCreateUserNumberLua()
/*
* keys1 随机前缀set 默认1至9,超过
* keys2 hash 存储前缀set对应的递增后的值
* argv1 随机数
* argv2 进位数 这里是5位 超过99999前缀set对应一个set进位
* 例如:
* 1.随机到前缀1 随机数为222 则生成的编号为 100222 hash存储前缀为1--》 222
* 2.再次随机到前缀1 随机数为333 则生成的编号为 100555 hash存储前缀为1--》 222
* 进位的情况
* 3.再次随机到前缀1 随机数为555(hash存储前缀为1--》 99998)则删除前缀为1的set,生成1+9=10的前缀,生成的编号为 1000555
*/
String script = "local prefix=0\\n" +
"local exists = redis.call('EXISTS', KEYS[1])\\n" +
"if exists == 1 then\\n" +
" prefix= redis.call('SRANDMEMBER', KEYS[1])\\n" +
"else\\n" +
" for i=1, 9 do redis.call('SADD', KEYS[1],i) end\\n" +
" prefix = redis.call('SRANDMEMBER', KEYS[1])\\n" +
"end\\n" +
"local currentNum = redis.call('hIncrBy', KEYS[2], prefix, ARGV[1])\\n" +
"if (currentNum > tonumber(ARGV[2])) then\\n" +
" local newPrefix = prefix + 9\\n" +
" local newCurrentNum = redis.call('hIncrBy', KEYS[2], newPrefix, ARGV[1])\\n" +
" redis.call('srem', KEYS[1], prefix)\\n" +
" redis.call('SADD', KEYS[1], newPrefix)\\n" +
" return (newPrefix * tonumber(ARGV[2])) + newCurrentNum\\n" +
"else\\n" +
" return (prefix * tonumber(ARGV[2])) + currentNum\\n" +
"end";
return redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(ACCOUNT_RANDOM_NUMBER_PREFIX_SET, ACCOUNT_RANDOM_NUMBER_HASH), RandomUtil.randomInt(100, 500), FIVE_DIGITS_MAX);
测试方法
@Test
public void initUserIdNumber() throws InterruptedException
CopyOnWriteArraySet<Long> set = new CopyOnWriteArraySet<>();
CountDownLatch latch = new CountDownLatch(1000);
for (int i = 0; i < 1000; i++)
new Thread(() ->
long lon = accountRegisterService.doCreateUserNumberLua();
System.out.println("lon=" + lon);
set.add(lon);
latch.countDown();
).start();
latch.await();
System.out.println("initUserIdNumber 完成");
System.out.println(set.size());
System.out.println(JSON.toJSONString(set));
以上是关于Redis Lua Java 随机编号 用户编号的主要内容,如果未能解决你的问题,请参考以下文章