All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.javaclub.toolbox.cache.redis.RedisStore Maven / Gradle / Ivy

There is a newer version: 2.7.44
Show newest version
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