redis單點緩存數據庫操作封裝

redis服務模塊封裝

redis單節點緩存數據庫操作分裝類;這篇博客對應上一篇博客CentOS7-源碼安裝redis單節點。此處,繼上次安裝好的redis之後,通過Java訪問redis,並將redis操作封裝成工具類。

包結構


其中:

——測試類:RedisTest

——服務類:RedisService

——工具類:RedisUtil

——配置文件:redis.properties

——配置文件備份:redis.bak


採用架構:Spring MVC

redis所需架包:


其中,被選中的*.src包爲源碼包,發佈的應用中不需要。


說明:項目僅引用redis的所需的包會報一個錯,logger日誌的所用類會找不到。源碼是logger日誌這裏用的是log4j的包,被整合在SpringMVC架構包中。解決方式可以將log4j對應的包導入,或者將logger的打印信息直接註釋,這也不影響redis服務類的使用。


配置文件信息

#Redis服務器IP
ADDR = 10.0.0.6
#Redis的端口號
PORT = 6379
#訪問密碼
AUTH = anson
#可用連接實例的最大數目,默認值爲8;
MAX_ACTIVE = 500
#控制一個pool最多有多少個狀態爲空閒的
MAX_IDLE = 500
#等待可用連接的最大時間,單位毫秒
MAX_WAIT = 10000
TIMEOUT = 10000
#在獲取一個jedis實例時,是否提前進行可用性判斷
TEST_ON_BORROW = true

RedisUtil工具類

package com.esh.redis;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

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

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

/**
 * @author Anson
 *	Copyright by EasyShare 2017
 *  
 *  All right reserved
 *
 *  Created on 2017年6月25日 下午4:12:56
 *  
 *  redis工具類
 */
public final class RedisUtil {
    
    //Redis服務器IP
    private static String ADDR;
    
    //Redis的端口號
    private static int PORT;
    
    //訪問密碼
    private static String AUTH;
    
    //可用連接實例的最大數目,默認值爲8;
    private static int MAX_ACTIVE;
    
    //控制一個pool最多有多少個狀態爲空閒的,默認值也是8。
    private static int MAX_IDLE;
    
    //等待可用連接的最大時間,單位毫秒,默認值爲-1,表示永不超時。
    private static int MAX_WAIT;
    
    private static int TIMEOUT;
    
    //在獲取一個jedis實例時,是否提前進行可用性判斷;如果爲true,則得到的jedis實例均是可用的;
    private static boolean TEST_ON_BORROW;
    
    private static JedisPool jedisPool = null;
    
    private static Logger logger=LoggerFactory.getLogger(RedisUtil.class.getName());
    
    /**
     * 初始化Redis連接池
     */
    static
    {
        try 
        {
        	//加載參數
           loadProperty();
        } catch (Exception e) 
        {
            e.printStackTrace();
        }
    }
    
    /**
     * 加載redis配置參數
     */
    private final static void loadProperty() {
		Properties prop=new Properties();
		try {
			prop.load(new FileInputStream(new File(Thread.currentThread().getContextClassLoader().getResource("").getPath()+"redis.properties")));
			ADDR=prop.getProperty("ADDR").trim();
			PORT=Integer.parseInt(prop.getProperty("PORT").trim());
			AUTH=prop.getProperty("AUTH");
			MAX_ACTIVE=Integer.parseInt(prop.getProperty("MAX_ACTIVE").trim());
			MAX_IDLE=Integer.parseInt(prop.getProperty("MAX_IDLE").trim());
			MAX_WAIT=Integer.parseInt(prop.getProperty("MAX_WAIT").trim());
			TIMEOUT=Integer.parseInt(prop.getProperty("TIMEOUT").trim());
			TEST_ON_BORROW=prop.getProperty("TEST_ON_BORROW").trim().toLowerCase().equals("true");
		
			logger.info("redis參數加載成功,"
					+ "參數:ADDR="+ADDR+" PORT="+PORT+" AUTH="+AUTH+
					"MAX_ACTIVE="+MAX_ACTIVE+"  MAX_IDLE="+MAX_IDLE+"  MAX_WAIT="+MAX_WAIT+"  TIMEOUT="+TIMEOUT+"  TEST_ON_BORROW="+TEST_ON_BORROW);
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

    
    /**
     * 創建redis池
     */
    private final static void initJedisPool() {
    	try
    	{
    		JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxTotal(MAX_ACTIVE);
            config.setMaxIdle(MAX_IDLE);
            config.setMaxWaitMillis(MAX_WAIT);
            config.setTestOnBorrow(TEST_ON_BORROW);
            jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
           // logger.info(jedisPool!=null?"redis池創建成功":"redis池創建失敗,位置:"+RedisUtil.class.getName());	
            logger.info(jedisPool!=null?"redis連接池創建成功":"");	
    	}catch(Exception e)
    	{
    		logger.error("第一次嘗試創建jedis連接池錯誤,位置:"+RedisUtil.class.getName());
    		try
    		{
    			JedisPoolConfig config = new JedisPoolConfig();
                config.setMaxIdle(MAX_ACTIVE);
                config.setMaxIdle(MAX_IDLE);
                config.setMaxWaitMillis(MAX_WAIT);
                config.setTestOnBorrow(TEST_ON_BORROW);
                jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
                logger.info(jedisPool!=null?"redis連接池創建成功":"");
    		}catch(Exception e1)
    		{
    			logger.error("第二次嘗試創建jedis連接池錯誤,位置:"+RedisUtil.class.getName());
    		}
    	}
  	}
    
    /**
     * 多線程下同步初始化
     */
    private synchronized static void loadPool()
    {
    	if(jedisPool==null)
    	{
    		initJedisPool();
    	}
    }
    
    
	/**
     * 同步獲取Jedis實例
     * @return
     */
    public synchronized static Jedis getJedis(){
    	if(jedisPool==null)
    	{
    		//未創建連接池是創建連接池
    		loadPool();
    	}
    	Jedis jedis=null;
        try
        {
            if (jedisPool != null) 
            {
                 jedis= jedisPool.getResource();
            }
        } catch (Exception e) 
        {
        	logger.info("獲取redis對象失敗,位置:"+RedisUtil.class.getName());
            e.printStackTrace();
        }
        return jedis;
    }
    

	/**
     * 釋放jedis資源
     * @param jedis
     */
	public synchronized static void close(final Jedis jedis){
        if (jedis!=null) 
        {
        	jedis.close();
        }
    }
}


RedisService服務類

package com.esh.redis;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;


/**
 * @author Anson
 *	Copyright by EasyShare 2017
 *  
 *  All right reserved
 *
 *  Created on 2017年6月25日 下午4:12:38
 *  
 *  redis服務類
 */
public class RedisService {
	
	private static Logger logger=LoggerFactory.getLogger(RedisService.class.getName());

	/**
	 * 通過key值獲取redis中的value,獲取後釋放鏈接
	 * @param key
	 * @return
	 * 		object
	 */
	public synchronized static Object get(String key)
	{
		Jedis jedis=null;
		byte[] value=null;
		Object obj=null;
		jedis=RedisUtil.getJedis();
		value=jedis.get(key.getBytes());
		if(value!=null)
		{
			obj=deSerialize(value);
		}
		RedisUtil.close(jedis);
		logger.info(obj!=null?"獲取緩存成功,":"獲取緩存數據失敗,位置:"+RedisService.class.getName());
		return obj;
	}
	
	/**
	 * 緩存一個對象,key存在則覆蓋
	 * @param key
	 * @param value
	 * @return
	 * 		boolean
	 */
	public synchronized static boolean set(String key, Object obj)
	{
		Jedis jedis=null;
		String code=null;
		jedis=RedisUtil.getJedis();
		code=jedis.set(key.getBytes(), serialize(obj));
		RedisUtil.close(jedis);
		logger.info(code.toLowerCase().equals("ok")?"緩存成功":"數據緩存失敗,位置:"+RedisService.class.getName());
		return code.toLowerCase().equals("ok");
	}
	
	/**
	 * 緩存一個鍵值對,key-value
	 * @param key
	 * @param value
	 * @return
	 * 		boolean
	 */
	public synchronized static boolean set(String key, String value)
	{
		Jedis jedis=null;
		String code=null;
		jedis=RedisUtil.getJedis();
		code=jedis.set(key.getBytes(), serialize(value));
		RedisUtil.close(jedis);
		logger.info(code.toLowerCase().equals("ok")?"緩存成功":"數據緩存失敗,位置:"+RedisService.class.getName());
		return code.toLowerCase().equals("ok");
	}
	
	/**
	 * redis批量寫入
	 * 事物操作
	 * 當前進行的事物操作,若對應的數據被其他進程修改,則該事物將被打斷
	 * @param objects
	 * 	Map<String, Object>
	 * @return
	 */
	public synchronized static boolean tset(Map<String, Object> objects)
	{
		Jedis jedis=null;
		List<Object> result=null;
		jedis=RedisUtil.getJedis();
		Transaction t=null;
		try {
			t=jedis.multi();
			for(Entry<String, Object> entry:objects.entrySet())
			{
				//監視數據
				t.watch(entry.getKey().getBytes());
				//保存數據
				t.set(entry.getKey().getBytes(), serialize(entry.getValue()));
			}
			result=t.exec();
		} catch (Exception e) {
			//回滾操作
			t.discard();
			logger.error("redis事物存儲失敗,位置:"+RedisService.class.getName());
		}
		RedisUtil.close(jedis);
		return result!=null;
	}
	
	/**
	 * 刪除key對應的緩存數據
	 * @param key
	 * @return
	 * 		boolean
	 */
	public synchronized static long del(String ...  keys)
	{
		Jedis jedis=null;
		long code=0;
		jedis=RedisUtil.getJedis();
		code=jedis.del(keys);
		RedisUtil.close(jedis);
		logger.info(code>1?"刪除成功":"緩存數據刪除失敗,位置:"+RedisService.class.getName());
		return code;
	}
	
	/**
	 * 批量刪除操作
	 * @param key
	 * @return
	 */
	public synchronized static long delbat(String key)
	{
		Jedis jedis=null;
		long code=0;
		jedis=RedisUtil.getJedis();
		Set<String> keySet=jedis.keys(key+"*");
		if(keySet!=null&&keySet.size()>0)
		{
			//將獲得的keys轉換成數組類型
			String[] keys=new String[keySet.size()];
			keySet.toArray(keys);
			code=jedis.del(keys);
		}
		RedisUtil.close(jedis);
		return code;
	}
	
	/**
	 * 清空數據庫
	 * @param isClearAll
	 * 		是否清空所有數據庫 
	 * 			false-清空當前使用的數據庫,默認爲0
	 * @return
	 * 		true||false
	 */
	public synchronized static boolean clear(boolean isClearAll)
	{
		Jedis jedis=null;
		String code=null;
		jedis=RedisUtil.getJedis();
		if(isClearAll)
		{
			code=jedis.flushAll();
			logger.info(code.toLowerCase().equals("ok")?"清空所有緩存數據庫成功":"清空所有緩存數據庫失敗");
		}else
		{
			code = jedis.flushDB();
			logger.info(code.toLowerCase().equals("ok")?"清空當前緩存數據庫清空成功":"清空當前緩存數據庫失敗");
		}
		RedisUtil.close(jedis);
		return code.toLowerCase().equals("ok");
	}
	
	/**
	 * 批量獲取操作
	 * @param key
	 * @return
	 */
	public synchronized static List<Object> getbat(String key)
	{
		Jedis jedis=null;
		List<Object> objects=new ArrayList<Object>();
		Object object=null;
		jedis=RedisUtil.getJedis();
		Set<String> keySet=jedis.keys(key+"*");
		RedisUtil.close(jedis);
		if(keySet!=null&&keySet.size()>0)
		{
			Iterator<String> it=keySet.iterator();
			while(it.hasNext())
			{
				String item=it.next();
				object=get(item);
				if(object!=null)
				{
					objects.add(object);
				}
			}
		}
		return objects;
	}
	
	
	/**
	 * 序列化存儲對象
	 * @param obj
	 * @return
	 */
	private synchronized static byte[] serialize(Object obj)
	{
		byte[] serialObj=null;
		ObjectOutputStream oos=null;
		ByteArrayOutputStream baos=null;
		try {
			baos=new ByteArrayOutputStream();
			oos=new ObjectOutputStream(baos);
			oos.writeObject(obj);
			serialObj=baos.toByteArray();
		} catch (IOException e) {
			e.printStackTrace();
		}finally
		{
			try {
				if(baos!=null)
				{
					baos.close();
				}
				if(oos!=null)
				{
					oos.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
				logger.error("釋放序列化資源失敗,位置:"+RedisService.class.getName());
			}
		}
		return serialObj;
	}
	
	/**
	 * 反序列化對象
	 * @param serialObj
	 * @return
	 */
	private synchronized static Object deSerialize(byte[] serialObj)
	{
		Object object=null;
		ObjectInputStream ois=null;
		ByteArrayInputStream bais=null;
		try {
			if(serialObj!=null&&serialObj.length>0)
			{
				bais=new ByteArrayInputStream(serialObj);
				ois=new ObjectInputStream(bais);
				object=ois.readObject();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}finally
		{
			try {
				if(bais!=null)
				{
					bais.close();
				}
				if(ois!=null)
				{
					ois.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
				logger.error("釋放反序列化資源失敗,位置:"+RedisService.class.getName());
			}
		}
		return object;
	}
}

測試類RedisTest代碼就不貼了,有興趣的自己copy源碼測試一波,博主自己在多線程環境下測試過所有服務功能,均可用,如有發現問題,亦可給我留言。

博主的測試環境是:

——redis單節點位置:CentOS7.2-x86-64;

——測試環境:Win7-x86-64,eclipse,jdk8,JMeter;

——測試最大並行線程量:8000;

——已發現並修正的問題:釋放jedis資源時,多線程下報錯;

另注意,如果redis數據庫節點位置與測試所用PC不在統一網絡上,需確保兩臺計算機之間通信穩定。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章