com.github.javaclub.toolbox.cache.redis.RedisStore Maven / Gradle / Ivy
package com.github.javaclub.toolbox.cache.redis;
import static com.github.javaclub.toolbox.ToolBox.Objects.requireNotEmpty;
import static com.github.javaclub.toolbox.ToolBox.Objects.requireTrue;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.javaclub.BizException;
import com.github.javaclub.Constants.AppDefaultConfig;
import com.github.javaclub.Constants.NetworkConfig;
import com.github.javaclub.Constants.RedisStoreConfig;
import com.github.javaclub.toolbox.ToolBox.IO;
import com.github.javaclub.toolbox.ToolBox.Numbers;
import com.github.javaclub.toolbox.ToolBox.Strings;
import com.github.javaclub.toolbox.cache.RedisStoreBuilder;
import com.github.javaclub.toolbox.conf.AppConfigPropertiesWatcher;
import com.github.javaclub.toolbox.conf.CompositeAppConfigProperties;
import com.github.javaclub.toolbox.thread.ExecutorServiceInstance;
import com.google.common.collect.Lists;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisPubSub;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;
import redis.clients.jedis.Tuple;
public class RedisStore {
private static final Logger logger = LoggerFactory.getLogger(RedisStore.class);
/**
* 标记 RedisStore 实例名称
*/
private String name;
// start Redis连接核心配置参数
private String host;
private int port;
private int db;
// end Redis连接核心配置参数
// 注意:Auth password参数不对外暴露
/**
* 当前 RedisStore 实例的连接池配置对象
*/
private JedisPoolConfig jedisPoolConfig;
private volatile JedisPool jedisPool = null; // 当前 RedisStore 实例的连接池对象
private volatile Jedis jedisSubscribeInstance = null; // 用于消息订阅
private RedisStore() {
}
private RedisStore(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public int getDb() {
return db;
}
public boolean isInstanceOf(String host, int port) {
return Objects.equals(this.host, host) && (this.port == port);
}
public boolean isInstanceOf(String host, int port, int db) {
return Objects.equals(this.host, host) && (this.port == port) && (this.db == db);
}
public JedisPool getJedisPool() {
return jedisPool;
}
public JedisPoolConfig getJedisPoolConfig() {
return jedisPoolConfig;
}
public boolean isReady() {
if ( !isConfiged() ) {
return false;
}
if (null == jedisPool) {
return false;
}
boolean ready = true;
String error = Strings.EMPTY;
try {
ready = isPingOK(jedisPool.getResource());
} catch (Exception e) {
ready = false;
error = e.getMessage();
} catch (Throwable e) {
ready = false;
error = e.getMessage();
} finally {
if (!ready && Strings.isNotBlank(error)) {
logger.error("Test isReady isPingOK=false, error={}", error);
}
if (null == jedisSubscribeInstance && ready) {
// 初始化消息订阅实例
jedisSubscribeInstance = jedisPool.getResource();
}
}
return ready;
}
public void destroy() {
IO.closeQuietly(jedisSubscribeInstance);
IO.closeQuietly(jedisPool);
logger.warn("RedisStore instance={} was destroying!", getName());
}
private static ConcurrentHashMap redisStoreMap = new ConcurrentHashMap();
private static volatile boolean defaultInstanceReady = false;
public static Map presentAll() {
return new TreeMap(redisStoreMap);
}
/**
* 取默认的RedisStore对象
*
* @return RedisStore对象
*/
public static RedisStore defaultPublic() {
String defaultKey = RedisStoreConfig.STORE_KEY_COMMON;
Map stores = presentAll();
if (null != stores && null != stores.get(defaultKey)
&& stores.get(defaultKey).isReady()) {
RedisStore store = stores.get(defaultKey);
if (!defaultInstanceReady) {
logger.info("RedisStore instance={} was selected as default.", store);
defaultInstanceReady = true;
}
return stores.get(defaultKey);
}
return RedisStoreBuilder.autoBuild(true);
}
public static boolean test(String host, int port, String password, int db) {
RedisStore store = new RedisStore(Strings.concat("_test_rs_", Strings.random(3, 6)));
try {
store.init(host, port, password, db);
return store.isReady();
} catch (Throwable e) {
logger.error("Error while testing RedisStore instance={} {host={}, port={}, password=******, db={}}: {}",
store.getName(), host, port, db, e.getMessage());
} finally {
store.destroy();
}
return false;
}
public static RedisStore createRedisStore(final String storeName, String[] redisConfigKeys) {
requireNotEmpty(storeName, "Parameter @storeName can't be empty");
requireTrue(null != redisConfigKeys && redisConfigKeys.length >= 4, "Redis configKeys must be specified");
RedisStore store = new RedisStore(storeName);
if (null == redisStoreMap.putIfAbsent(storeName, store)) {
String host = CompositeAppConfigProperties.getInstance().getValue(redisConfigKeys[0]);
int port = CompositeAppConfigProperties.getInstance().intValue(redisConfigKeys[1], 6379);
String password = CompositeAppConfigProperties.getInstance().getValue(redisConfigKeys[2]);
int db = CompositeAppConfigProperties.getInstance().intValue(redisConfigKeys[3], 0);
boolean suc = store.init(host, port, password, db);
logger.info("RedisStore instance={} build {} with config: {host={}, port={}, password=******, db={}}",
storeName, suc ? "successfully" : "failed", host, port, db);
new AppConfigPropertiesWatcher(redisConfigKeys) {
@Override
protected void doOnChange() {
String host = CompositeAppConfigProperties.getInstance().getValue(redisConfigKeys[0]);
int port = CompositeAppConfigProperties.getInstance().intValue(redisConfigKeys[1]);
String password = CompositeAppConfigProperties.getInstance().getValue(redisConfigKeys[2]);
int db = CompositeAppConfigProperties.getInstance().intValue(redisConfigKeys[3]);
logger.info("AppConfigPropertiesWatcher watch CompositeAppConfigProperties redisConfig changed {}",
Lists.newArrayList(host, port, Strings.filter(password), db));
RedisStore.reInitStore(storeName, host, port, password, db);
}
}.start();
}
return redisStoreMap.get(storeName);
}
public static RedisStore createRedisStore(String storeName, String host, int port, String password, int db) {
RedisStore store = new RedisStore(storeName);
if (null == redisStoreMap.putIfAbsent(storeName, store)) {
boolean suc = store.init(host, port, password, db);
logger.info("RedisStore instance={} build {} with config: {host={}, port={}, password=******, db={}}",
storeName, suc ? "successfully" : "failed", host, port, db);
}
return redisStoreMap.get(storeName);
}
public static void reInitStore(String storeName, String host, int port, String password, int db) {
RedisStore store = redisStoreMap.get(storeName);
if (null != store) {
boolean suc = store.init(host, port, password, db);
logger.info("RedisStore instance={} rebuild {} with config: {host={}, port={}, password=******, db={}}",
storeName, suc ? "successfully" : "failed", host, port, db);
}
}
public static RedisStore getRedisStore(String storeName) {
return redisStoreMap.get(storeName);
}
public void publishMessage(String channel, String message) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.publish(channel, message);
} catch (Throwable th) {
logger.error("Jedis publishMessage fail, channel={}, message={}, error={}",
channel, message, th.getMessage());
} finally {
IO.closeQuietly(jedis);
}
}
public void subscribeMessage(final JedisPubSub jedisPubSub, final String... channels) {
try {
if (null == jedisSubscribeInstance) {
jedisSubscribeInstance = jedisPool.getResource();
}
boolean checkOK = false;
try {
checkOK = jedisSubscribeInstance.isConnected() && isPingOK(jedisSubscribeInstance);
} catch (Exception e) {
checkOK = false;
}
if (!checkOK) {
IO.closeQuietly(jedisSubscribeInstance);
jedisSubscribeInstance = jedisPool.getResource();
logger.info("Get a new jedisSubscribeInstance");
}
ExecutorServiceInstance.get(AppDefaultConfig.REDIS_STORE_SUBSCRIBER_EXECUTOR, 3).execute(new Runnable() {
@Override
public void run() {
jedisSubscribeInstance.subscribe(jedisPubSub, channels);
}
});
logger.info("Jedis subscribeMessage on redisTopics={}", Arrays.asList(channels));
} catch (Throwable th) {
logger.error("Jedis subscribeMessage fail, channel={}, error={}, host={}, port={}, db={}",
channels, th.getMessage(), host, port, db);
} finally {
// 这里不要关闭,否则:消息队列订阅会有问题
// IO.closeQuietly(jedisSubscribeInstance);
}
}
private boolean isConfiged() {
return (Strings.isNotBlank(host) && port > 0 && db >= 0);
}
private boolean isPingOK(Jedis jedis) throws Throwable {
try {
if (null != jedis) {
String pingResp = jedis.ping();
return Strings.equalsIgnoreCase("PONG", pingResp);
}
} catch (Throwable e) {
throw e;
} finally {
IO.closeQuietly(jedis);
}
return false;
}
private boolean init(String host, int port, String password, int db) {
String config = Strings.format("host={}, port={}, password={}, db={}", host, port, Strings.filter(password), db);
boolean checkValid = (Strings.isNotBlank(host) && port > 0 && db >= 0);
if ( !checkValid ) {
logger.error("Illegal Arguments for redis init config: {}", config);
return false;
}
this.jedisPoolConfig = RedisStoreBuilder.newCustomJedisPoolConfig();
// 网络连接超时时间/读取超时时间;Jedis里其实是共用同一个值(原始默认值为2000毫秒)
int netTimeout = NetworkConfig.getTimeout();
JedisPool oldPool = jedisPool;
JedisPool newPool = new JedisPool(jedisPoolConfig, host, port, netTimeout, password, db);
boolean isOK = false;
try {
isOK = isPingOK(newPool.getResource());
} catch (Throwable e) {
isOK = false;
String error = Strings.format("RedisStore init failed with config: {}", config);
throw new BizException(error, e);
}
if (isOK) {
this.host = host;
this.port = port;
this.db = db;
this.jedisPool = newPool;
IO.closeQuietly(oldPool);
}
return isOK;
}
public boolean hasKey(String key) throws Throwable {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
Boolean exists = jedis.exists(key);
return null != exists ? exists.booleanValue() : false;
} catch (Throwable th) {
logger.error("Jedis get fail, key={}, host={}, port={}, db={}, error={}",
key, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public String get(String key) throws Throwable {
String value = null;
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
value = jedis.get(key);
} catch (Throwable th) {
logger.error("Jedis get fail, key={}, host={}, port={}, db={}, error={}",
key, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
return value;
}
public void set(String key, String value) throws Throwable {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
value = jedis.set(key, value);
} catch (Throwable th) {
logger.error("Jedis set fail, key={}, host={}, port={}, db={}, error={}",
key, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public void set(String key, String value, int expiredSeconds) throws Throwable {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.setex(key, expiredSeconds, value);
} catch (Throwable th) {
logger.error("Jedis set with expire fail, key={}, host={}, port={}, db={}, error={}",
key, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public void set(String key, String value, long mills) throws Throwable {
Jedis jedis = null;
try {
int seconds = Numbers.createBigDecimal(String.valueOf(mills/1000)).intValue();
jedis = jedisPool.getResource();
jedis.setex(key, seconds, value);
} catch (Throwable th) {
logger.error("Jedis set with expire fail, key={}, host={}, port={}, db={}, error={}",
key, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public boolean setIfAbsent(String key, String value, long timeout, TimeUnit unit) throws Throwable {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
Long ret = jedis.setnx(key, value);
boolean setNX = Objects.equals(1L, ret);
if (!setNX) {
String redisVal = get(key);
if (!Objects.equals(value, redisVal)) {
return false;
}
}
Long expireAtRet = jedis.expireAt(key, (new Date().getTime() + unit.toMillis(timeout)) / 1000L);
return Objects.equals(1L, expireAtRet);
} catch (Throwable th) {
logger.error("Jedis setIfAbsent fail, key={}, host={}, port={}, db={}, error={}",
key, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public boolean setNX(String key, String value) throws Throwable {
Jedis jedis = null;
Long ret = null;
try {
jedis = jedisPool.getResource();
ret = jedis.setnx(key, value);
return Objects.equals(1L, ret);
} catch (Throwable th) {
logger.error("Jedis set with expire fail, key={}, host={}, port={}, db={}, error={}",
key, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
/**
* 指定时间点过期,如:
*
*
* redisStore.expireAt(key, DateUtil.plusHours(new Date(), 2).getTime() / 1000L);
*
*
* @param key redisKey
* @param unixTimeSecs 自1970-01-01 00:00:00以来的秒数
*/
public void expireAt(String key, long unixTimeSecs) throws Throwable {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.expireAt(key, unixTimeSecs);
} catch (Throwable th) {
logger.error("Jedis expireAt fail, key={}, expireAt={}, host={}, port={}, db={}, error={}",
key, unixTimeSecs, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public boolean expire(String key, long expiredInSeconds) {
Long timestamp = System.currentTimeMillis() + expiredInSeconds * 1000L;
try {
expireAt(key, timestamp / 1000L);
return true;
} catch (Throwable th) {
logger.error("Jedis expire fail, key={}, expiredInSeconds={}, host={}, port={}, db={}, error={}",
key, expiredInSeconds, host, port, db, th.getMessage());
}
return false;
}
public void del(String key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.del(key);
} catch (Throwable th) {
logger.error("Jedis del fail, key={}, host={}, port={}, db={}, error={}",
key, host, port, db, th.getMessage());
// throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public void delMultiKeys(String... keys) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.del(keys);
} catch (Throwable th) {
logger.error("Jedis delMultiKeys fail, multiKeysSize={}, host={}, port={}, db={}, error={}",
keys.length, host, port, db, th.getMessage());
// throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public Set getCollection(String key) throws Throwable {
Jedis jedis = null;
Set value = null;
try {
jedis = jedisPool.getResource();
value = jedis.smembers(key);
} catch (Throwable th) {
logger.error("Jedis get collection fail, key={}, host={}, port={}, db={}, error={}",
key, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
return value;
}
public Long addCollection(String key, String... values) throws Throwable {
Jedis jedis = null;
Long ret = null;
try {
jedis = jedisPool.getResource();
ret = jedis.sadd(key, values);
} catch (Throwable th) {
logger.error("Jedis add collection fail, key={}, host={}, port={}, db={}, error={}",
key, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
return ret;
}
public Long delFromCollection(String key, String... values) throws Throwable {
Jedis jedis = null;
Long ret = null;
try {
jedis = jedisPool.getResource();
jedis.srem(key, values);
} catch (Throwable th) {
logger.error("Jedis srem fail, key={}, host={}, port={}, db={}, error={}",
key, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
return ret;
}
public Long zadd(String key, Double score, String memberValue) throws Throwable {
Jedis jedis = null;
Long ret = null;
try {
jedis = jedisPool.getResource();
ret = jedis.zadd(key, score, memberValue);
} catch (Throwable th) {
logger.error("Jedis zadd fail, key={}, score={}, value={}, host={}, port={}, db={}, error={}",
key, score, memberValue, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
return ret;
}
public Long zadd(String key, Map scoreMembers) throws Throwable {
Jedis jedis = null;
Long ret = null;
try {
jedis = jedisPool.getResource();
ret = jedis.zadd(key, scoreMembers);
} catch (Throwable th) {
int size = (null == scoreMembers) ? 0 : scoreMembers.size();
logger.error("Jedis zadd fail, key={}, scoreMembersSize={}, host={}, port={}, db={}, error={}",
key, size, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
return ret;
}
public Long zrem(String key, Collection members) throws Throwable {
Jedis jedis = null;
Long ret = null;
try {
jedis = jedisPool.getResource();
ret = jedis.zrem(key, members.toArray(new String[0]));
} catch (Throwable th) {
logger.error("Jedis zrem fail, key={}, host={}, port={}, db={}, error={}",
key, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
return ret;
}
public Set zrangeByScoreWithScores(String key, Double min, Double max) throws Throwable {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.zrangeByScoreWithScores(key, min, max);
} catch (Throwable th) {
logger.error("Jedis zrangeByScoreWithScores fail, key={}, minScore={}, maxScore={}, host={}, port={}, db={}, error={}",
key, min, max, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public String hmset(String key, Map hashMap) throws Throwable {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.hmset(key, hashMap);
} catch (Throwable th) {
logger.error("Jedis hmset fail, key={}, hash={}, host={}, port={}, db={}, error={}",
key, hashMap, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public Long hset(String key, String hashKey, String hashValue) throws Throwable {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.hset(key, hashKey, hashValue);
} catch (Throwable th) {
logger.error("Jedis hset fail, key={}, hashKey={}, hashValue={}, host={}, port={}, db={}, error={}",
key, hashKey, hashValue, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public String hget(String key, String hashKey) throws Throwable {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.hget(key, hashKey);
} catch (Throwable th) {
logger.error("Jedis hget fail, key={}, hashKey={}, host={}, port={}, db={}, error={}",
key, hashKey, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public List hmget(String key, String... fields) throws Throwable {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.hmget(key, fields);
} catch (Throwable th) {
logger.error("Jedis hmget fail, key={}, fields={}, host={}, port={}, db={}, error={}",
key, Arrays.asList(fields), host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public Map hgetAll(String key) throws Throwable {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.hgetAll(key);
} catch (Throwable th) {
logger.error("Jedis hgetAll fail, key={}, host={}, port={}, db={}, error={}",
key, host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public Set hkeys(String key) throws Throwable {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.hkeys(key);
} catch (Throwable th) {
logger.error("Jedis hkeys fail, key={}, host={}, port={}, db={}, error={}", key, host, port, db,
th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public List hvalues(String key) throws Throwable {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.hvals(key);
} catch (Throwable th) {
logger.error("Jedis hvals fail, key={}, host={}, port={}, db={}, error={}", key, host, port, db,
th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
public Boolean hexists(String key, String hashKey) throws Throwable {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.hexists(key, hashKey);
} catch (Throwable th) {
logger.error("Jedis hexists fail, key={}, hashKey={}, host={}, port={}, db={}, error={}", key, hashKey,
host, port, db, th.getMessage());
throw th;
} finally {
IO.closeQuietly(jedis);
}
}
/**
* Redis 执行scan扫描
*
* @param pattern 表达式,需要过滤的key
* @param count 每次扫描个数
* @param callback 业务处理
*/
public boolean scan(String pattern, int count, RedisScanCallback callback) {
Jedis jedis = null;
boolean suc = false;
try {
jedis = jedisPool.getResource();
String cursor = ScanParams.SCAN_POINTER_START; // redis游标初始值为0
ScanParams scanParams = new ScanParams();
scanParams.match(pattern);// "monitor:*:" 匹配以 monitor: 为前缀的key
scanParams.count(count > 0 ? count : 1000);
while (true) {
boolean needBreak = callback.breakScanDecision();
if (needBreak) {
return false; // 终止不处理
}
ScanResult scanResult = jedis.scan(cursor, scanParams);
cursor = scanResult.getCursor(); // 返回 0 说明遍历已完成
callback.handle(scanResult.getResult());
if (Objects.equals(ScanParams.SCAN_POINTER_START, cursor)) {
suc = true;
break;
}
}
} catch (Exception e) {
suc = false;
logger.error("Jedis scan fail, keyPattern={}, scanCount={}, host={}, port={}, db={}, error={}", pattern,
count, host, port, db, e.getMessage());
throw e;
} finally {
IO.closeQuietly(jedis);
}
return suc;
}
public Long incr(String key) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.incr(key);
} catch (Throwable e) {
throw new BizException(e);
} finally {
IO.closeQuietly(jedis);
}
}
public Long incrBy(String key, long delta) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.incrBy(key, delta);
} catch (Throwable e) {
throw new BizException(e);
} finally {
IO.closeQuietly(jedis);
}
}
/**
* 生成全局唯一的自增ID
*/
public long nextId(String ns, boolean random) {
// 1.生成时间戳
LocalDateTime now = LocalDateTime.now();
long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
long timestamp = nowSecond - AppDefaultConfig.GEN_ID_START_TIMESTAMP;
// 2.生成序列号
// 2.1.获取当前日期,精确到天
String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
String incrKey = RedisKeys.custom("incr").dir(date).end(ns).build();
// 2.2.自增长 incr:2023:08:28:biz_order
long step = AppDefaultConfig.GEN_ID_STEP;
long count = 0L;
if (random) { // 随机趋势递增
count = incrBy(incrKey, step);
count = count + Numbers.random(1L, step - 1);
} else { // 单调 +1 递增
count = incr(incrKey);
}
// 3.拼接并返回 timestamp << COUNT_BITS :向左移动32位
// 原本时间戳在低位上,通过向左移动32位,变位到高位存储,低32位都是0,然后与自增序列按位操作
// 形成低32位为序列号。
return timestamp << AppDefaultConfig.GEN_ID_COUNT_BITS | count;
}
/**
* 生成唯一流水编号
*
* @param bits 位数
* @param prefix 前缀
* @param ns namespace
* @return 流水号编号
*/
public String flowNo(int bits, String prefix, String ns) {
LocalDateTime now = LocalDateTime.now();
String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
String incrKey = RedisKeys.custom("incr").dir(date).end(ns).build();
long no = incr(incrKey);
String str = Strings.expand(String.valueOf(no), bits, '0', true);
if (Strings.isBlank(prefix)) {
return str;
}
return Strings.concat(prefix, str);
}
@Override
public String toString() {
String format = "{}:[host={},port={},password=******,db={}]";
return Strings.format(format, Strings.noneNull(name).toUpperCase(), host, port, db);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy