redis工具类-示例

应公司架构原因,没有使用spring,于是就只能自己编一个redis工具类,请大家多多指教。

redisUtils 工具类

package com.bpe.core.db;

import java.io.Serializable;
import java.util.List;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.bpe.core.util.BPEProperty;
import com.bpe.core.util.ExceptionUtil;

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

/**
 * redis 帮助类
 *  
 * @author bpe
 *
 */
public class RedisUtil implements Serializable{

	private static Logger log = LoggerFactory.getLogger(RedisUtil.class);

	private static final long serialVersionUID = -1149678082569464779L;

	//可用连接实例的最大数目,默认值为8;
	//如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
	private static int maxActive = 400;

	//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
	private static int maxIdle = 10;

	//等待可用连接的最大数目;
	private static int maxWait = 1000;

	//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
	// private static int timeOut = 6000;

	//在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
	private static boolean testOnBorrow = false;

	public static Jedis jedis;//非切片额客户端连接

	public static JedisPool jedisPool;//非切片连接池

	public static int count = 0; //初始化jedis连接池数量

	{
		//静态内部类在类加载时就创建对象,JVM的机制保证了类在加载时是互斥的,所以也是线程安全的
		try {
			/*log.info("\n----------------------------------------------------------\n\t" +
					"  RedisUtil initialPool(); \n\t" +
					"  RedisUtil getJedis(); \n\t" +
					"  RedisUtil 静态代码块初始化jedis连接池;\n" +
					"----------------------------------------------------------");*/
			initialPool();
			getJedis();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 初始化非切片池
     * 单例模式创建连接池且线程安全
	 */
	static void initialPool() 
	{ 
		if (jedisPool == null){
			synchronized (RedisUtil.class){
				if (jedisPool == null){
					count ++;
					// 池基本配置 
					JedisPoolConfig config = new JedisPoolConfig();
					config.setMaxTotal(maxActive); 
					config.setMaxIdle(maxIdle); 
					config.setMaxWaitMillis(maxWait); 
					config.setTestOnBorrow(testOnBorrow);
					jedisPool = new JedisPool(config, BPEProperty.JP.dbTyp.redis.host, 
							Integer.parseInt(BPEProperty.JP.dbTyp.redis.port));
					log.info("jedisPool is null 初始化连接池---数量====["+count+"]");
				}
			}
		}
	}

	//初始化
	public static void getJedis() throws Exception {
		try {
			jedis = new JedisProxy(jedisPool).createProxy();
		} catch (Exception e) {
			ExceptionUtil.log(log, e);
			System.out.println("连接jedisPool失败!");
		}

	}

	public static void closeJedis() throws Exception {
		try {
			if (jedis != null) {
				jedis.close();
			}
		} catch (Exception e) {
			closeBrokenResource(jedis);
			System.out.println("close jedisPool error");
		}
	}

	/**
	 * Return jedis connection to the pool, call different return methods depends on whether the connection is broken 
	 */
	protected static void closeBrokenResource(Jedis jedis) {
		try {
			System.out.println("closeBrokenResource start");
		} catch ( Exception e ) {
			destroyJedis(jedis);
		}
	}

	/**
	 * 在 Jedis Pool 以外强行销毁 Jedis
	 */
	public static void destroyJedis(Jedis jedis) {
		if ( jedis != null ) {
			try {
				jedis.quit();
			} catch (Exception e ) {
				System.out.println(">>> RedisUtil-jedis.quit() : " + e );
			}
			try {
				jedis.disconnect();
			}catch (Exception e ) {
				System.out.println(">>> RedisUtil-jedis.disconnect() : " + e );
			}
		}
	}

	/**	 
	 * String 新增
	 * @param key
	 * @param value
	 */
	public static void setStr(String key, String value, int expireSecond) {
		try {
			initialPool();
			if (jedis == null) {
				getJedis();
			}
			//jedis.set(key.getBytes(), SerializableUtil.serializable(value));
			jedis.set(key, value);
			if (expireSecond > 0) {
				jedis.expire(key, expireSecond);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * String 删除
	 * @param key
	 */
	public void removeStr(String key) {
		try {
			initialPool();
			if (jedis == null) {
				getJedis();
			}
			jedis.del(key);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}


	/**
	 * String 查询
	 * @param key
	 * @return
	 */
	public static String getStr(String key) {
		try {
			initialPool();
			System.out.println(jedisPool);
			if (jedis == null) {
				getJedis();
			}
			/*byte[] bytes = jedis.get(key.getBytes());
				String str = null;
				if (bytes != null) {
					str = String.valueOf(SerializableUtil.unSerializable(bytes));
				}*/
			String str = jedis.get(key);
			return str;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * String 查询
	 * @param key
	 * @return
	 */
	public static Long getTTl(String key) {
		Long time = 0L;
		initialPool();
		if (jedis != null) {
			try {
				//以秒为单位,返回 key 的剩余生存时间。
				time = jedis.ttl(key);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return time;
	}

	/**
	 * list 新增操作
	 * @param key
	 * @param value
	 * vlaue可以是一个string数组,也可以是单个字符串
	 */
	public static void setList(String key,String...value) {
		try {
			initialPool();
			if (jedis == null) {
				getJedis();
			}
			jedis.lpush(key, value);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * list 删除操作
	 * @param key
	 * @param count
	 * @param value
	 */
	public static void removeList(String key,int count,String value) {
		try {
			initialPool();
			if (jedis == null) {
				getJedis();
			}
			jedis.lrem(key, count, value);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * list 长度
	 * @param key
	 */
	public static Long findListSize(String key) {
		try {
			initialPool();
			Long size = jedis.llen(key);
			return size;
		} catch (Exception e) {
			e.printStackTrace();
			log.info("Redis:{}","connect error");
		}try {
			closeJedis();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 模糊查询所有的key
	 */
	public static Set<String> findAllKeys(String findName) {
		Set<String> keys=null;
		try {
			//			getJedis();
			keys = jedis.keys("*"+findName+"*");
		} catch (Exception e) {
			e.printStackTrace();
			log.info("Redis:{}","connect error");
		}finally {
			try {
				closeJedis();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return keys;
	}

	/** redis list 增删改查***********************start*/
	/**
	 * 添加一个集合对象
	 * @param key
	 * @param value
	 * value可以是一个string数组,也可以是单个字符串
	 *
	 */
	public static void addList(String key, String ...value) {
		try {
			initialPool();
			if (jedis == null) {
				getJedis();
			}
			jedis.lpush(key, value);
		} catch (Exception e) {
			e.printStackTrace();
			log.info("Redis:{}","connect error");
		}
	}

	/**
	 * 获取list
	 * @param key
	 * @param start 开始
	 * @param end 结束
	 * @return
	 * 区间以偏移量 start 和 end 指定。 其中 0 表示列表的第一个元素,
	 * 1 表示列表的第二个元素,以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素,
	 * -2 表示列表的倒数第二个元素,以此类推
	 */
	public static List<String> getList(String key, int start, int end){
		List<String> list = null;
		try {
			initialPool();
			if (jedis == null) {
				getJedis();
			}
			//获取指定长度的list集合
			list = jedis.lrange(key, start, end);
		} catch (Exception e) {
			e.printStackTrace();
			log.info("Redis:{}","connect error");
		}
		return list;
	}

	/**
	 * 更新List
	 * @param key
	 * @param index 索引
	 * @param value
	 * 通过索引来设置元素的值
	 */
	public static void setValue(String key,int index,String value){
		try {
			initialPool();
			if (jedis == null) {
				getJedis();
			}
			//获取指定长度的list集合
			jedis.lset(key, index, value);
		} catch (Exception e) {
			e.printStackTrace();
			log.info("Redis:{}","connect error");
		}
	}

	/**
	 * 删除List
	 * @param key
	 * @param count
	 * @param value
	 * count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT 。
	 * count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为 COUNT 的绝对值。
	 * count = 0 : 移除表中所有与 VALUE 相等的值。
	 */
	public static void removeValue(String key,int count,String value){
		try {
			initialPool();
			if (jedis == null) {
				getJedis();
			}
			jedis.lrem(key, count, value);
		} catch (Exception e) {
			e.printStackTrace();
			log.info("Redis:{}","connect error");
		}
	}
}

JedisHandler

package com.bpe.core.db;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.InvocationHandler;

import com.bpe.core.util.BPEProperty;

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

public class JedisHandler implements InvocationHandler {

	private JedisPool jedisPool;

	public JedisHandler(JedisPool jedisPool){
		this.jedisPool = jedisPool;
	}


	/**
	 * 当使用jedis方法的时候,实际调用的这里的方法
	 * @param proxy
	 * @param method
	 * @param args
	 * @return
	 * @throws Throwable
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Jedis jedis = null;
		try {
			if (jedisPool == null) {
				RedisUtil.initialPool();
				System.out.println("RedisUtil jedisPool is null 再次初始化连接池");
			}
			jedis = jedisPool.getResource();
			if(!"127.0.0.1".equals(BPEProperty.JP.dbTyp.redis.host)) {
				jedis.auth(BPEProperty.JP.dbTyp.redis.pwd);
			}else {
				jedis.auth(BPEProperty.JP.dbTyp.redis.pwd);
			}
			Object invoke = method.invoke(jedis, args);
			return invoke;
		}finally {
                   //开始关闭redis资源
			if (jedis != null) {
				jedis.close();
			}
		}
	}


}

JedisProxy

package com.bpe.core.db;

import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;

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

/**
 * spring cglib 动态代理关闭redis资源
 * @author bpe
 */
public class JedisProxy {

	private JedisPool jedisPool;
	 
    public JedisProxy(JedisPool jedisPool) {
        this.jedisPool = jedisPool;
    }
 
    public Jedis createProxy() throws Exception{
        Enhancer enhancer = new Enhancer();
        //设置代理的父类,就设置需要代理的类
        enhancer.setSuperclass(Jedis.class);
        //设置自定义的代理方法
        Callback callback = new JedisHandler(jedisPool);
        enhancer.setCallback(callback);
 
        Object o = enhancer.create();
        Jedis jedis = null;
        if (o instanceof Jedis){
            jedis = (Jedis) o;
        }
        return jedis;
    }
}

java使用redis一般都是通过redis.clients.jedis.Jedis来连接redis服务器,通过redis.clients.jedis.Jedis提供的方法使用redis

 

但是每次执行完jedis里面的方法之后必须关闭链接,释放资源,否则链接一旦用完下次再使用redis程序会堵塞,但是手动关闭链接或出现很多的重复代码,并且有些时候也会忘记关闭

 

解决方法就是使用代理模式来解决这一问题

 

代理有两种:java的Proxy类和Spring的Enhancer

 

区别就是前者只能代理基于接口的类,也就是说代理的类必须是接口,否则无法代理

 

后者是Spring的代理类,弥补java的Proxy只能代理接口的缺陷

 

Enhancer使用非常简单,只要使用了Spring就会有,全类目是org.springframework.cglib.proxy.Enhancer

 

以后获取Jedis对象通过new JedisProxy().createProxy(),使用jedis的方法都会自动关闭连接了

————————————————

后面还是有一部分东西不全,比如对于连接池满了该如何做,是阻塞还是其他等等。

在这里博主就不深究了

Guess you like

Origin blog.csdn.net/qq_35731570/article/details/102519374