Redis连接池

Redis连接池

Redis 是单进程单线程的,它利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。

Redis 是基于内存的数据库,使用之前需要建立连接,建立断开连接需要消耗大量的时间。

再假设 Redis 服务器与客户端分处在异地,虽然基于内存的 Redis 数据库有着超高的性能,但是底层的网络通信却占用了一次数据请求的大量时间,因为每次数据交互都需要先建立连接,假设一次数据交互总共用时 30ms,超高性能的 Redis 数据库处理数据所花的时间可能不到 1ms,也即是说前期的连接占用了 29ms,连接池则可以实现在客户端建立多个连接并且不释放,当需要使用连接的时候通过一定的算法获取已经建立的连接,使用完了以后则还给连接池,这就免去了数据库连接所占用的时间。

Jedis resource = jedisPool.getResource();

注意,这行代码。我们从 JedisPool 中获取的仅仅是一个连接。至于多个连接到达单进程单线程的 Redis 之后怎么处理,就与线程池无关了。

实际上,Redis 在收到多个连接后,采用的是非阻塞 IO,基于 epoll 的多路 IO 复用。

然后采用队列模式将并发访问变为串行访问,对于串行访问,本身操作内存就很快,Redis 采用一个线程来处理就再正常不过了。

Redis连接池的使用与配置

在 Java 中使用Redis连接池需要两个 jar 包 commons-pool2-2.4.2.jar 跟 jedis-2.9.0.jar

配置连接池
因为连接池中会有很多jedis实例,RedisPool对象会很大,所以我们需要把他写成单例模式,如果是交由Spring管理就不用了,因为Spring管理的Bean默认是单例的。

// 连接信息
private static final String HOST = "132.232.6.208";
private static final int PORT = 6381;

JedisPoolConfig poolConfig = new JedisPoolConfig();
// 基本配置
poolConfig.setMaxTotal(1000);           // 最大连接数
poolConfig.setMaxIdle(32);              // 最大空闲连接数
poolConfig.setMaxWaitMillis(100*1000);  // 最大等待时间
poolConfig.setTestOnBorrow(true);       // 检查连接可用性, 确保获取的redis实例可用
                    
JedisPool jedisPool = new JedisPool(poolConfig, HOST, PORT);

获取连接池连接

Jedis jedis = jedisPool.getResource();

将连接归还连接池

jedisPool.returnResourceObject(jedis);  // 已废弃,推荐使用jedis.close()方法

jedis.close()

完整代码

package com.project.uitl;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * Redis 连接池工具包
 * @author wqj24
 *
 */
public class JedisPoolUtil {
    
    private static final String HOST = "132.232.6.208";
    private static final int PORT = 6381;
    
    private static volatile JedisPool jedisPool = null;
    
    private JedisPoolUtil() {}
    
    /**
     * 获取RedisPool实例(单例)
     * @return RedisPool实例
     */
    public static JedisPool getJedisPoolInstance() {
        if (jedisPool == null) {
            synchronized (JedisPoolUtil.class) {
                if (jedisPool == null) {
                    
                    JedisPoolConfig poolConfig = new JedisPoolConfig();
                    poolConfig.setMaxTotal(1000);           // 最大连接数
                    poolConfig.setMaxIdle(32);              // 最大空闲连接数
                    poolConfig.setMaxWaitMillis(100*1000);  // 最大等待时间
                    poolConfig.setTestOnBorrow(true);       // 检查连接可用性, 确保获取的redis实例可用
                    
                    jedisPool = new JedisPool(poolConfig, HOST, PORT);
                }
            }
        }
        
        return jedisPool;
    }
    
    /**
     * 从连接池中获取一个 Jedis 实例(连接)
     * @return Jedis 实例
     */
    public static Jedis getJedisInstance() {
        
        return getJedisPoolInstance().getResource();
    }
    
    /**
     * 将Jedis对象(连接)归还连接池
     * @param jedisPool 连接池
     * @param jedis 连接对象
     */
    public static void release(JedisPool jedisPool, Jedis jedis) {
        
        if (jedis != null) {
            jedisPool.returnResourceObject(jedis);  // 已废弃,推荐使用jedis.close()方法
        }
    }
}

测试代码

package com.project.test;

import org.junit.Test;

import com.project.uitl.JedisPoolUtil;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class RedisPoolTest {
    
    JedisPool jedisPool = JedisPoolUtil.getJedisPoolInstance();
    
    // 测试单例
    @Test
    public void test01() {
        JedisPool A = JedisPoolUtil.getJedisPoolInstance();
        JedisPool B = JedisPoolUtil.getJedisPoolInstance();

        System.out.println(A == B);
    }
    
    @Test
    public void test02() {
        Jedis jedis = null;
        
        try {
            jedis = jedisPool.getResource();  // 获取Redus连接
            
            // 业务
            jedis.set("k1", "v111");
            System.out.println(jedis.get("k1"));
        } finally {
            jedis.close(); // 关闭redis连接
        }
    }
}

Redis连接池配置及初始化

加入db选择后的Redis连接池配置代码

public class RedisPoolConfigure {

    //Redis服务器IP
    private String ADDR ;
    
    //Redis的端口号
    private int PORT ;
    
    //可用连接实例的最大数目
    private  int MAX_ACTIVE ;
    
    //pool中的idle jedis实例数
    private  int MAX_IDLE ;
    
    //等待可用连接的最大时间,单位毫秒
    private  int MAX_WAIT ;
    //超时时间,单位毫秒
    private  int TIME_OUT ;
    //设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数)
    private String EVICTION_POLICY_CLASS_NAME ;
    
    //连接耗尽时是否阻塞, false报异常,ture阻塞直到超时
    private boolean BLOCK_WHEN_EXHAUSTED;
    
    //是否启用pool的jmx管理功能, 默认true
    private boolean JMX_ENABLED;
    
    //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
    private boolean TEST_ON_BORROW ;
    
    //服务器密码
    private String REDIS_PASS;
    //redis选择数据库DB
    private int REDIS_DB;
    
    
    private String LUASHA;
    
    private  Map<String, String> configure = null;
    
    /**
     * 根据配置文件,将RedisPool连接配置初始化
     */
    public RedisPoolConfigure(){
    	try {
    		configure = new ConfigureReader().readProperties("redis.properties");
		} catch (IOException e) {
			e.printStackTrace();
		}
    	this.ADDR = configure.get("REDIS.ADDR");
    	this.LUASHA = configure.get("REDIS.LUA_HASH");
    	this.EVICTION_POLICY_CLASS_NAME = configure.get("REDIS.EVICTION_POLICY_CLASS_NAME");
    	this.BLOCK_WHEN_EXHAUSTED = Boolean.parseBoolean(configure.get("REDIS.BLOCK_WHEN_EXHAUSTED"));
    	this.JMX_ENABLED = Boolean.parseBoolean(configure.get("REDIS.JMX_ENABLED"));
    	this.TEST_ON_BORROW = Boolean.parseBoolean(configure.get("REDIS.TEST_ON_BORROW"));
    	this.REDIS_PASS=configure.get("REDIS.PASS");
    	
    	if(typeCheck()){
    		this.PORT = new Integer(configure.get("REDIS.PORT"));
    		this.MAX_ACTIVE = new Integer(configure.get("REDIS.MAX_ACTIVE"));
    		this.MAX_IDLE = new Integer(configure.get("REDIS.MAX_IDLE"));
    		this.MAX_WAIT = new Integer(configure.get("REDIS.MAX_WAIT"));
    		this.REDIS_DB=new Integer(configure.get("REDIS.DB"));
    	}else{
    		System.out.println("error");
    	}
    }
    
    /**
     * 辅助工具,检查map中数据的类型
     * @return
     */
	private boolean typeCheck() {
		if (isNumeric(configure.get("REDIS.PORT")) 
				&& isNumeric(configure.get("REDIS.MAX_ACTIVE"))
				&& isNumeric(configure.get("REDIS.MAX_IDLE")) 
				&& isNumeric(configure.get("REDIS.MAX_WAIT"))
				&& isNumeric(configure.get("REDIS.DB"))) {
			return true;
		} 
		return false;
	}

	public String getADDR() {
		return ADDR;
	}

	public int getPORT() {
		return PORT;
	}


	public int getMAX_ACTIVE() {
		return MAX_ACTIVE;
	}

	public int getMAX_IDLE() {
		return MAX_IDLE;
	}

	public int getMAX_WAIT() {
		return MAX_WAIT;
	}

	public int getTIME_OUT() {
		return TIME_OUT;
	}

	public boolean isTEST_ON_BORROW() {
		return TEST_ON_BORROW;
	}

	public String getEVICTION_POLICY_CLASS_NAME() {
		return EVICTION_POLICY_CLASS_NAME;
	}

	public boolean isBLOCK_WHEN_EXHAUSTED() {
		return BLOCK_WHEN_EXHAUSTED;
	}

	public boolean isJMX_ENABLED() {
		return JMX_ENABLED;
	}
	/**
	 * 判断传入的数据是否为纯数字构成
	 * @param str
	 * @return
	 */
	public boolean isNumeric(String str) {
		if(str==null || "".equals(str)){
			return false;
		}
		for (int i = 0; i < str.length(); i++) {
			if (!Character.isDigit(str.charAt(i))) {
				return false;
			}
		}
		return true;
	}

	public String getLUASHA() {
		return LUASHA;
	}

	public void setLUASHA(String lUASHA) {
		LUASHA = lUASHA;
	}

	public String getREDIS_PASS() {
		return REDIS_PASS;
	}

	public void setREDIS_PASS(String rEDIS_PASS) {
		REDIS_PASS = rEDIS_PASS;
	}

	public int getREDIS_DB() {
		return REDIS_DB;
	}

	public void setREDIS_DB(int rEDIS_DB) {
		REDIS_DB = rEDIS_DB;
	}
}

Redis连接池初始化、获取Jedis实例和释放Jedis实例

/**
 * jedis的连接池,返回未封装的jedis对象
 * 一般只有在RedisCache类提供的操作粒度不足使用时才使用此类提供的原生jedis方法
 * @author Hector
 *
 */
public class RedisPool {
	 
    private static JedisPool jedisPool = null;
    
    /**
     * 初始化Redis连接池
     */
    static {
        try {
        	RedisPoolConfigure configure = new RedisPoolConfigure();
            JedisPoolConfig config = new JedisPoolConfig();
            config.setBlockWhenExhausted(configure.isBLOCK_WHEN_EXHAUSTED());
            config.setEvictionPolicyClassName(configure.getEVICTION_POLICY_CLASS_NAME());
            config.setJmxEnabled(configure.isJMX_ENABLED());
            config.setMaxIdle(configure.getMAX_IDLE());
            config.setMaxTotal(configure.getMAX_ACTIVE());
            config.setMaxWaitMillis(configure.getMAX_WAIT());
            config.setTestOnBorrow(configure.isTEST_ON_BORROW());
            jedisPool = new JedisPool(config, configure.getADDR(), configure.getPORT(), configure.getTIME_OUT(),configure.getREDIS_PASS(),configure.getREDIS_DB());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 获取Jedis实例
     * @return
     */
    public synchronized static Jedis getJedis() {
    	Jedis resource=null;
        try {
            if (jedisPool != null) {
                resource = jedisPool.getResource();
                return resource;
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
   
    /**
     * 释放jedis资源
     * @param jedis
     */
	public static void close(final Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }
	
	public static JedisPool getJedisPool() {
		return jedisPool;
	}
}

参考文章:
https://www.xttblog.com/?p=3823
https://www.jianshu.com/p/f7cb5235a892
https://blog.csdn.net/weixin_38994249/article/details/82774326

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值