美文网首页
使用Redis和Redis连接池作为缓存

使用Redis和Redis连接池作为缓存

作者: PigPIgAutumn | 来源:发表于2018-02-23 09:18 被阅读0次

    redis是作为缓存一个非常好的解决方案,但是redis也相当于一个数据库,其在同一时间的可用连接是有限的,在高并发下必须使用redis连接池来确保服务器内存安全以及数据能正确正常地存储到redis中.

    同时,使用redis连接池的好处有:
    1.复用连接,减少建立/释放连接的消耗
    2.确保数据能正确写入redis缓存中

    代码如下:

    public class JedisUtil {
    
        private static Logger logger = LoggerFactory.getLogger(JedisUtil.class);
    
        private static String redisHost = Config.getRedisHost();
        private static int redisPort = Config.getRedisPort();
        private static int redisDB = Config.getRedisDB();
        private static String auth = Config.getRedisPassword();
        /**redis连接池设置**/
        private static int MAX_POOL_SIZE = Config.getRedisPoolSize();
        private static JedisPool pool;
        /**缓存的过期时间**/
        private static int CACHE_TIMEOUT = 3;
    
        public static String getRedisHost(){
            return redisHost;
        }
    
        public static int getRedisPort(){
            return redisPort;
        }
    
        public static int getRedisDB(){
            return redisDB;
        }
    
        public static String getAuth(){
            return auth;
        }
    
        /**
         * 初始化连接池,加上同步,避免多线程下重复初始化
         */
        public static synchronized void initJedisPool(){
            //static修饰的代码会比实例对象更快执行
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            jedisPoolConfig.setMaxTotal(MAX_POOL_SIZE);
            pool = new JedisPool(jedisPoolConfig, redisHost, redisPort);
        }
    
        /**
         * 从连接池中获取jedis实例
         * @return
         */
        public static Jedis getJedisInstance(){
            if (pool == null) initJedisPool();
            return pool.getResource();
        }
    
        /**
         * 从redis获取键为key的值
         * @param key 键
         * @return redis中键为key的value
         */
        public static String getString(String key){
            String value = null;
            Jedis jedis = null;
            try{
                jedis = getJedisInstance();
                value = jedis.get(key);
            } catch (NoSuchElementException noe){
                logger.warn("jedis instance in JedisPool has been Exhausted");
                noe.printStackTrace();
            } catch (JedisConnectionException jce){
                logger.warn("jedis instance in JedisPool has been Exhausted and wait for timeout");
                jce.printStackTrace();
            } finally {
                if (jedis != null) jedis.close();
            }
            return value;
        }
    
        /**
         * 将键值对(key, value)存进redis,并设置过期时间为timeout,单位是ms
         * @param key key
         * @param value value
         * @param timeout 过期时间
         */
        public static void setString(String key, String value, int timeout){
            Jedis jedis = null;
            try{
                jedis = getJedisInstance();
                jedis.set(key,value);
                jedis.expire(key, timeout);
            }catch (NoSuchElementException noe){
                logger.warn("jedis instance in JedisPool has been Exhausted");
                noe.printStackTrace();
            } catch (JedisConnectionException jce){
                logger.warn("jedis instance in JedisPool has been Exhausted and wait for timeout");
                jce.printStackTrace();
            } finally {
                if (jedis != null) jedis.close();
            }
        }
    
        /**
         * 使用默认的过期时间存储键值对
         * @param key key
         * @param value value
         */
        public static void setString(String key, String value){
            setString(key, value, CACHE_TIMEOUT);
        }
    
        /**
         * 检查key是否存在
         * @param key key
         * @return boolean
         */
        public static boolean containsKey(String key){
            Jedis jedis = null;
            try{
                jedis = getJedisInstance();
                return jedis.exists(key);
            } catch (NoSuchElementException noe){
                logger.warn("jedis instance in JedisPool has been Exhausted");
                noe.printStackTrace();
            } catch (JedisConnectionException jce){
                logger.warn("jedis instance in JedisPool has been Exhausted and wait for timeout");
                jce.printStackTrace();
            } finally {
                if (jedis != null) jedis.close();
            }
            return false;
        }
    
        public static void removeKey(String key){
            Jedis jedis = null;
            try{
                jedis = getJedisInstance();
                jedis.del(key);
            } catch (NoSuchElementException noe){
                logger.warn("jedis instance in JedisPool has been Exhausted");
                noe.printStackTrace();
            } catch (JedisConnectionException jce){
                logger.warn("jedis instance in JedisPool has been Exhausted and wait for timeout");
                jce.printStackTrace();
            } finally {
                if (jedis != null) jedis.close();
            }
        }
    
        /**
         * 关闭redis连接池
         */
        public static void close(){
            if (pool != null) pool.close();
        }
    }
    
    

    关键点有以下几点:
    1.Jedis实例就相当于一个redis的连接,因此,每次进行操作使用的jedis对象实例必须是从JedisPool中获取的,这样才能复用连接

    2.每次使用jedis实例对象后,都必须调用jedis.close()将redis连接归还到连接池,高版本的jedis直接调用close()就能归还连接,低版本需要调用其他方法

    3.每次获取jedis实例对象不一定会成功,当连接耗尽后会抛出
    NoSuchElementException,这就必须捕获这个异常,要么阻塞线程,要么丢弃这次操作,由于radius协议是基于udp的,可靠性要求比较低,所以我的redis连接池就直接丢弃这个操作了.

    相关文章

      网友评论

          本文标题:使用Redis和Redis连接池作为缓存

          本文链接:https://www.haomeiwen.com/subject/jbvtxftx.html