Redis作為緩存數據庫理論上和MySQL一樣需要客戶端和服務端建立起來連接進行相關操作,使用MySQL的時候相信大家都會使用一款開源的連接池,例如C3P0.因為直連會消耗大量的數據庫資源,每一次新建一個連接之,使用后再斷開連接,對於頻繁訪問的場景,這顯然不是高效的。
Jedis直連Redis
生產環境一般使用連接池的方式對Redis連接進行管理,所有Jedis對象先放在池子中每一次需要的時候連接Redis,只需要在池子中借,用完了再歸還給池子。
Jedis連接池使用方式
客戶端連接Redis使用的是TCP協議,直連的方式每次需要建立TCP連接,而連接池的方式是可以預先初始化好Jedis連接,所以每次只需要從Jedis連接池借用即可,而借用和歸還操作是在本地進行的,只有少量的並發同步開銷,遠遠小於新建TCP連接的開銷。另外直連的方式無法限制Jedis對象的個數,在極端情況下可能會造成連接泄露,而連接池的形式可以有效的保護和控制資源的使用。但是直連的方式也並不是一無是處,下面給出兩種方式各自的優劣勢。
Jedis直連方式和連接池方式對比
Jedis提供了JedisPool這個類作為對Jedis的連接池。使用如下:
1 public class RedisPool { 2 //聲明成static的原因:保證jedis連接池在tomcat啟動時就加載出來 3 //jedis連接池 4 private static JedisPool pool; 5 //與redis連接池連接的最大連接數 6 private static Integer maxTotal = Integer.parseInt(PropertiesUtil.getProperty("redis.max.total", "20")); 7 //在這個連接池中最多有多少個狀態為idle的jedis實例,jedis連接池里就是jedis的實例,idle就是空閑的jedis實例 8 //在jedis連接池中最大的idle狀態(空閑的)的jedis實例的個數 9 private static Integer maxIdle = Integer.parseInt(PropertiesUtil.getProperty("redis.max.idle", "10")); 10 //在jedis連接池中最小的idle狀態(空閑的)的jedis實例的個數 11 private static Integer minIdle = Integer.parseInt(PropertiesUtil.getProperty("redis.min.idle", "2")); 12 13 //在borrow一個jedis實例的時候,是否要進行驗證操作,如果賦值為true,則得到的jedis實例肯定是可用的 14 private static Boolean testOnBorrow = Boolean.parseBoolean(PropertiesUtil.getProperty("redis.test.borrow", "true")); 15 //在return一個jedis實例的時候,是否要進行驗證操作,如果賦值為true,則返回jedis連接池的jedis實例肯定是可用的 16 private static Boolean testOnReturn = Boolean.parseBoolean(PropertiesUtil.getProperty("redis.test.return", "true")); 17 18 private static String redisIp = PropertiesUtil.getProperty("redis.ip"); 19 private static Integer redisPort = Integer.parseInt(PropertiesUtil.getProperty("redis.port")); 20 21 //初始化連接池,只會調用一次 22 private static void initPool() { 23 JedisPoolConfig config = new JedisPoolConfig(); 24 25 config.setMaxTotal(maxTotal); 26 config.setMaxIdle(maxIdle); 27 config.setMinIdle(minIdle); 28 29 config.setTestOnBorrow(testOnBorrow); 30 config.setTestOnReturn(testOnReturn); 31 32 //連接池耗盡的時候,是否阻塞,false會拋出異常,true阻塞直到超時,會拋出超時異常,默認為true 33 config.setBlockWhenExhausted(true); 34 35 //這里超時時間是2s 36 pool = new JedisPool(config, redisIp, redisPort, 1000*2); 37 38 } 39 40 static { 41 initPool(); 42 } 43 44 //從連接池中拿取一個實例 45 public static Jedis getJedis() { 46 return pool.getResource(); 47 } 48 49 //將正常實例放回jedis連接池 50 public static void returnResource(Jedis jedis) { 51 pool.returnResource(jedis); 52 } 53 54 //將破損實例放回jedis連接池 55 public static void returnBrokenResource(Jedis jedis) { 56 pool.returnResource(jedis); 57 } 58 59 }
JedisPoolUtil向外提供的工具類如下所示:

1 public class RedisPoolUtil { 2 3 //重新設置有效期 4 //參數只有key和有效期,因為只需要根據key設置有效期即可 5 public static Long expire(String key, int exTime) { 6 Jedis jedis = null; 7 Long result = null; 8 try { 9 jedis = RedisPool.getJedis(); 10 //設置有效期 11 result = jedis.expire(key, exTime); 12 } catch (Exception e) { 13 log.error("setex key:{} error", key, e); 14 RedisPool.returnBrokenResource(jedis); 15 return result; 16 } 17 RedisPool.returnResource(jedis); 18 return result; 19 } 20 21 //exTime單位是s,設置session有效時間 22 //當用戶初次登錄的時候,需要設置有限期,存在redis session中 23 //后續如果用戶再次請求登錄,則只需要調用expire,重新設置有效期即可 24 public static String setEx(String key, String value, int exTime) { 25 Jedis jedis = null; 26 String result = null; 27 try { 28 jedis = RedisPool.getJedis(); 29 result = jedis.setex(key, exTime, value); 30 } catch (Exception e) { 31 log.error("setex key:{} value:{} error", key, value, e); 32 RedisPool.returnBrokenResource(jedis); 33 return result; 34 } 35 RedisPool.returnResource(jedis); 36 return result; 37 } 38 39 public static String set(String key, String value) { 40 Jedis jedis = null; 41 //jedis返回的結果 42 String result = null; 43 try { 44 jedis = RedisPool.getJedis(); 45 //設置key-value 46 result = jedis.set(key, value); 47 } catch (Exception e) { 48 log.error("set key:{} value:{} error", key, value, e); 49 RedisPool.returnBrokenResource(jedis); 50 return result; 51 } 52 RedisPool.returnResource(jedis); 53 return result; 54 } 55 56 public static String get(String key) { 57 Jedis jedis = null; 58 String result = null; 59 try { 60 jedis = RedisPool.getJedis(); 61 //根據key獲取value值 62 result = jedis.get(key); 63 } catch (Exception e) { 64 log.error("set key:{} error", key, e); 65 RedisPool.returnBrokenResource(jedis); 66 return result; 67 } 68 RedisPool.returnResource(jedis); 69 return result; 70 } 71 72 public static Long del(String key) { 73 Jedis jedis = null; 74 Long result = null; 75 try { 76 jedis = RedisPool.getJedis(); 77 //根據key刪除key-value 78 result = jedis.del(key); 79 } catch (Exception e) { 80 log.error("set key:{} error", key, e); 81 RedisPool.returnBrokenResource(jedis); 82 return result; 83 } 84 RedisPool.returnResource(jedis); 85 return result; 86 } 87 }