一:簡介
在瀏覽本篇文章時務必要會Redis的基本命令,因為在一些主流語言中使用一些其它Redis客戶端時都是基於基本命令來操作的;比如在java項目中使用連接Redis客戶端有Jedis、Redisson、Jredis、JDBC-Redis;不過官方推薦我們使用Jedis和Redisson;本文章中我會使用Jedis和SpringDataRedis來操作遠程的Redis服務端。
Jedis封裝了Redis的一些命令操作,它是Redis的Java客戶端,和我們在Redis自帶的客戶端輸入的命令一樣,Jedis也提供了連接池管理,可以不用每次關閉連接Redis而消耗時間。
SpringDataRedis是Spring大家族的一部分,提供了在Spring應用中通過簡單的配置訪問Redis服務,對Redis底層開發包(Jedis, JRedis, and RJC)進行了高度封裝,RedisTemplate提供了redis各種操作、異常處理及序列化,支持發布訂閱等,不過在高版本中SpringDataRedis底層則不在使用Jedis。(后續介紹SpringDataRedis)
1:務必看看
注:本篇文章的命令都在我之前的 【Redis命令】 一文中都詳細說明了,我也是參照那篇文章轉換為Java程序來實現;遇到不會的命令只須參照【Redis命令】一文 Ctrl+F 直接搜索那個命令即可;而且使用Jedis只要找到你需要的方法,方法參數和官方命令順序都是一樣的,而且簡單易上手,主要是知道某個命令干啥的就行;還有就是我的文章只是參考,具體的大家可以參考官方文檔!
二:Jedis繼承關系分析
1:Jedis類
Jedis提供了Redis客戶端的連接和命令查詢,從Jedis繼承關系中發現它實現很多的命令接口,每個接口都定義了不同的操作形式,這符合面向對象開發原則中的接口隔離原則和單一職責原則。下面的接口聲明了相關的redis命令操作,每個接口都負責對一部分的命令進行方法聲明
Jedis父類BinaryJedis所依賴的接口: BasicCommands:
提供基礎的查詢命令,如ping,quit,flushdb
BinaryJedisCommands:
提供了針對redis數據結構的CURD等操作,其中參數(K-V)必須以byte數組形式提供
MultiKeyBinaryCommands:
提供了針對redis數據結構的CURD等批量操作,其中參數(K-V)必須以byte數組形式提供
AdvancedBinaryJedisCommands:
提供高級操作redis的命令,如config相關,slowlog,client等命令,其中參數(K-V)必須以byte數組形式提供
BinaryScriptingCommands:
提供Lua腳本運行命令,命令必須以byte數組形式提供。
Jedis所依賴的接口: JedisCommands:
提供了針對redis數據結構的CURD等操作,其中參數(K-V)必須以String形式提供
MultiKeyCommands:
提供了針對redis數據結構的CURD等批量操作,其中參數(K-V)必須以String數組形式提供
AdvancedJedisCommands:
提供高級操作redis的命令,如config相關,slowlog,client等命令,其中參數(K-V)必須以String形式提供
ScriptingCommands:
提供Lua腳本運行命令,命令必須以String形式提供。
BasicCommands:
提供如ping,quit,flushDb運維類命令
ClusterCommands:
提供集群狀態查看,集群操作的命令
SentinelCommands:
提供哨兵操作命令
ModuleCommands:
提供redis模塊加載和卸載命令
2:Client類
除了方法接口聲明之外,Jedis還提供了客戶端Client,使用該類仍然可以連接Redis服務端並進行相關的命令操作。Client本身只是提供相關的命令方法,這些方法聲明定義在Commands接口,連接操作則定義在Connection類,也就是說Client類類似於一個前台,可以提供各種服務,而具體的實現則依賴於Connection和Commands,Client提供方法與Jedis基本一致,不同的是Client類里獲取命令是沒有返回值的,所有我們一般不用Client,都是使用Jedis,不過Jedis底層必須有Client的存在
Client所依賴的接口: Commands:
內部都是Redis基本命令的封裝
Client所繼承的類: BinaryClient:
用來最終和Redis服務端交互的客戶端,以二進制交互,內部繼承Connection類
3:Jedis如何發送命令到Redis服務端
Jedis是通過Socket對Redis服務端進行連接的,而Jedis和Client本身並沒有Socket連接方法的實現,相關的連接方法都在Connection類中,觀察繼承關系,Connection類是其頂層的實現類。Jedis或者Client發送命令時,必須通過Connection類的connect()方法建立TCP連接。
在使用Connection類時,需提供相關的參數進行實例化,從構造方法可以看到,需要提供主機名,如果不設置,則使用默認名localhost.連接端口,不設置則使用默認端口6379,連接超時時長(如果不進行設置,則默認與socketTimeout保持一致),Socket讀取超時時長(如果不進行設置,則使用默認時長2000ms),SSL加密傳輸則是可選的。在連接時必須判斷當前對象的連接狀態,如果符合條件則新建Socket實例。
Jedis和Client類通過Connection對象的sendCommand()方法進行命令傳輸,在傳輸命令時必須將字符串轉為字節數組,如果類似於ping,ask這樣的命令,只需要將命令轉為字節即可。轉換完成之后寫入到輸出流中,將字節流發送給Redis 服務端。
三:Jedis操作使用
1:基本案例
基本案例中我使用maven的一個空項目(maven骨架:maven-archetype-quickstart)來進行簡單的操作;
<!--導入Jedis坐標,用來操作Redis的,主要就這個包--> <dependencies> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.7.0</version> </dependency> <!--導入fastjson,用於對象的轉換JSON格式--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.78</version> </dependency> </dependencies>
public static void main(String[] args){ //創建一個連接 Jedis jedis = new Jedis("localhost", 6379); //ping一下Redis服務端是否在線,成功則返回 “PONG” 反之報錯超時 String ping = jedis.ping(); //Jedis它實現了各式各樣接口,最終匯聚一個類Jedis,它內部封裝了全部Redis命令 //比如下面的”String類型命令set“保存兩條數據,保存成功則返回ok jedis.set("name","zhangsan"); jedis.set("age","22"); //在redis中獲取name值 String name = jedis.get("name"); System.out.println(name); jedis.close();//關閉連接 //也可以直接使用Client,但是我們還是使用Jedis吧,讓Jedis底層調用Client吧,我們直接使用是沒有返回值的 Client client = new Client("localhost", 6379); client.set("name","lisi"); client.close(); }
2:Jedis連接池

#最大活動對象數 redis.pool.maxTotal=1000 #最大能夠保持idel狀態的對象數 redis.pool.maxIdle=100 #最小能夠保持idel狀態的對象數 redis.pool.minIdle=50 #當池內沒有返回對象時,最大等待時間 redis.pool.maxWaitMillis=10000 #當調用borrow Object方法時,是否進行有效性檢查 redis.pool.testOnBorrow=true #當調用return Object方法時,是否進行有效性檢查 redis.pool.testOnReturn=true #“空閑鏈接”檢測線程,檢測的周期,毫秒數。如果為負值,表示不運行“檢測線程”。默認為-1 redis.pool.timeBetweenEvictionRunsMillis=30000 #向調用者輸出“鏈接”對象時,是否檢測它的空閑超時 redis.pool.testWhileIdle=true # 對於“空閑鏈接”檢測線程而言,每次檢測的鏈接資源的個數。默認為3 redis.pool.numTestsPerEvictionRun=50 #redis服務器的IP redis.ip=localhost #redis服務器的Port redis.port=6379 #連接Redis超時時間秒 redis.timeout=2000 #連接Redis的password,不寫則沒有密碼 redis.password=

import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import java.io.IOException; import java.io.InputStream; import java.time.Duration; import java.util.Properties; /** * @Author AnHui_XiaoYang * @Email 939209948@qq.com * @Date 2021/10/17 20:44 * @Description Jedis連接池工具 */ public class JedisPoolUtils { private static JedisPool jedisPool; static { //類加載時,讀取配置文件 InputStream in = JedisPoolUtils.class.getClassLoader().getResourceAsStream("jedisPool.properties"); //創建Properties對象並關聯對象 Properties pro = new Properties(); try { pro.load(in); } catch (IOException e) { e.printStackTrace(); } //創建連接池配置並設置值 JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(Integer.parseInt(pro.getProperty("redis.pool.maxTotal"))); config.setMaxIdle(Integer.parseInt(pro.getProperty("redis.pool.maxIdle"))); config.setMinIdle(Integer.parseInt(pro.getProperty("redis.pool.minIdle"))); config.setMaxWaitMillis(Long.parseLong(pro.getProperty("redis.pool.maxWaitMillis"))); config.setTestOnBorrow(Boolean.parseBoolean(pro.getProperty("redis.pool.testOnBorrow"))); config.setTestOnReturn(Boolean.parseBoolean(pro.getProperty("redis.pool.testOnReturn"))); Duration duration = Duration.ofMinutes(Long.parseLong(pro.getProperty("redis.pool.timeBetweenEvictionRunsMillis"))); config.setTimeBetweenEvictionRuns(duration); config.setTestWhileIdle(Boolean.parseBoolean(pro.getProperty("redis.pool.testWhileIdle"))); config.setNumTestsPerEvictionRun(Integer.parseInt(pro.getProperty("redis.pool.numTestsPerEvictionRun"))); String host = pro.getProperty("redis.ip"); Integer port = Integer.valueOf(pro.getProperty("redis.port")); Integer timeout = Integer.valueOf(pro.getProperty("redis.timeout")); String password = pro.getProperty("redis.password"); if (password == null || "".equals(password)) jedisPool = new JedisPool(config, host, port, timeout); else jedisPool = new JedisPool(config, host, port, timeout, password); } /** * @return 返回一個JedisClient */ public static Jedis getJedisClient() { return jedisPool.getResource(); } }
public static void main(String[] args) { //平時使用連接池對象即可,每次都重新創建獲取會消耗大量時間 Jedis jedis = JedisPoolUtils.getJedisClient(); jedis.set("name","zhangsan"); String s = jedis.get("name"); System.out.println(s); jedis.close();//不用時直接close即可 }
總結:現在在項目中一般不會單獨引用Jedis了,通常會以SpringBoot集成Redis,通過RedisTemplate模板來操作Redis;具體使用請參考 SpringDataRedis入門到深入