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

2018-02-23  本文已影响0人  PigPIgAutumn

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连接池就直接丢弃这个操作了.

上一篇下一篇

猜你喜欢

热点阅读