Redisによる一意の順序のプライマリ・キーの生成


分散型プロジェクトでは、一意のプライマリ・キーを生成したり、順序番号を生成したりするのによく使用されます.Redisによって順序番号の生成が実現されます.
あまり話さないで、直接コードをつけます.
1、唯一のキーファクトリメソッドインタフェースを生成するのは以下の通りである.
/**
 *           
 */
public interface SequenceFactory {
    /**
     *               
     * @param seqKey   
     * @return       
     */
    long nextValue(String seqKey);

    /**
     *       ,                    24  
     * @param seqKey   
     * @return   
     */
    long dailyNextValue(String seqKey);
}

1、実現方式一

/**
 *    Lua     
 */
public class RedisLuaSequenceFactory implements SequenceFactory {

    private static final long SEQ_START_ID = 0L;
    private static final int DEFAULT_EXPIRE = 3600 * 24;
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
    private static final String LUA_SCRIPT = "local key = KEYS[1]
" + "local expire = ARGV[1]
" + "local isExp = nil ~= expire and -1 ~= tonumber(expire)
" + "local exists = redis.call('EXISTS', key)
" + "local seq = 0
" + "if( exists == 0) then
" + " redis.call('SET', key, 0)
" + "else
" + " seq = redis.call('INCR', key)
" + " if( seq < 0) then
" + " redis.call('SET', key, 0)
" + " seq = 0
" + " end
" + "end
" + "
" + "local ttl = redis.call('TTL', key)
" + "if( isExp and ttl == -1) then
" + " redis.call('EXPIRE', key, expire)
" + "end
" + "return seq"; private Jedis jedis; public RedisLuaSequenceFactory(Jedis jedis){ this.jedis = jedis; } @Override public long nextValue(String seqKey) { return value(seqKey, "-1"); } @Override public long dailyNextValue(String seqKey) { String today = LocalDate.now().format(FORMATTER); String key = today + ":" + seqKey; return value(key, String.valueOf(DEFAULT_EXPIRE)); } private long value(String key, String expire){ Object eval = jedis.eval(LUA_SCRIPT, Collections.singletonList(key), Collections.singletonList(expire)); return (Long) eval; } }

luaスクリプトは以下の通りです
--[[
         ID
--]]
local key = KEYS[1]
local expire = ARGV[1]
local isExp = nil ~= expire and -1 ~= tonumber(expire) --           
local seq = 0
local exists = redis.call('EXISTS', key) --    key    
if( exists == 0) then
    redis.call('SET', key, 0) --               0
else
    --                 ,     ,         0
    seq = redis.call('INCR', key)
    if( seq < 0) then
        redis.call('SET', key, 0)
        seq = 0
    end
end

--           ,          ,            
local ttl = redis.call('TTL', key)
if( isExp and ttl == -1) then
    redis.call('EXPIRE', key, expire)
end
return seq