Jedis使用操作


一:簡介

  在瀏覽本篇文章時務必要會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=
jedisPool.properties
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();
    }
}
JedisPoolUtil連接工具類
    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入門到深入


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM