網站首頁 編程語言 正文
一、摘要
在上一篇文章中,我們詳細的介紹了 redis 的安裝和常見的操作命令,以及可視化工具的介紹。
剛知道服務端的操作知識,還是遠遠不夠的,如果想要真正在項目中得到應用,我們還需要一個 redis 的客戶端,然后將其集成到項目中,讓程序自動根據我們的業務需要自動處理。
基于 redis 開放的通信協議,大神們紛紛開發了各種語言的 redis 客戶端,有 c、c++、java、python、php、nodeJs 等等開發語言的客戶端,準確來說其實這些客戶端都是基于 redis 命令做了一層封裝,然后打包成工具以便大家更佳方便的操作 redis,以 Java 項目為例,使用最廣的就是以下三種客戶端:
- Jedis
- Lettuce
- Redisson
由于篇幅的原因,我們分三篇文章來詳細的講解每個客戶端的使用方式以及它的優缺點。
廢話不多說,直奔主題!
二、Jedis
Jedis 是老牌的 Redis 的 Java 客戶端,提供了比較全面的 Redis 命令的操作支持,也是目前使用最廣泛的客戶端。
官方網址如下:
https://github.com/redis/jedis
如何在項目中集成 Jedis 呢?請看下文!
2.1、基本使用
首先創建一個普通的 Maven 項目,然后添加Jedis
依賴包!
<dependency> ??<groupId>redis.clients</groupId> ??<artifactId>jedis</artifactId> ??<version>3.9.0</version> </dependency>
然后創建一個簡單的測試,即可實現連接!
public?class?JedisMain?{ ????public?static?void?main(String[]?args)?{ ????????//?1.構造一個?Jedis?對象,因為這里使用的默認端口?6379,所以不用配置端口 ????????Jedis?jedis?=?new?Jedis("127.0.0.1",?6379); ????????//?2.密碼認證 ????????jedis.auth("111111"); ????????//?3.測試是否連接成功 ????????String?ping?=?jedis.ping(); ????????//?4.返回?pong?表示連接成功 ????????System.out.println(ping); ????} }
對于 Jedis 而言,一旦連接上了 Redis 服務器,剩下的操作就非常容易了,由于 Jedis 中的 API 和 Redis 的命令高度一致,所以,Jedis 中的方法見名知意,直接使用即可。
2.2、連接池
雖然 redis 服務端是單線程操作,但是在實際項目中,使用 Jedis 對象來操作 redis 時,每次操作都需要新建/關閉 TCP 連接,連接資源開銷很高,同時 Jedis 對象的個數不受限制,在極端情況下可能會造成連接泄漏,同時 Jedis 存在多線程不安全的問題。
為什么說 Jedis 線程不安全,更加詳細的原因可以參考:使用Jedis面臨的非線程安全問題詳解
所以我們需要將 Jedis 交給線程池來管理,使用 Jedis 對象時,從連接池獲取 Jedis,使用完成之后,再還給連接池。
在使用之前,需要添加common-pool
線程池依賴包!
<dependency> ?<groupId>org.apache.commons</groupId> ?<artifactId>commons-pool2</artifactId> ?<version>2.11.1</version> </dependency>
創建一個簡單的使用線程池測試用例。
public?class?JedisPoolMain?{ ????public?static?void?main(String[]?args)?{ ????????//?1.?構造一個?Jedis?連接池 ????????JedisPool?pool?=?new?JedisPool("127.0.0.1",?6379); ????????//?2.?從連接池中獲取一個?Jedis?連接 ????????Jedis?jedis?=?pool.getResource(); ????????jedis.auth("111111"); ????????//?3.?Jedis?操作 ????????String?ping?=?jedis.ping(); ????????System.out.println(ping); ????????//?4.?歸還連接 ????????jedis.close(); ????} }
2.3、連接池配置
在實際的使用過程中,我們常常會這樣來初始化線程池JedisPool
,詳細代碼如下:
public?class?RedisPoolUtils?{ ????private?static?JedisPool?jedisPool?=?null; ????/** ?????*?redis服務器地址 ?????*/ ????private?static?String?addr?=?"127.0.0.1"; ????/** ?????*?redis服務器端口 ?????*/ ????private?static?int?port?=?6379; ????/** ?????*?redis服務器密碼 ?????*/ ????private?static?String?auth?=?"111111"; ????static{ ????????try?{ ????????????JedisPoolConfig?config?=?new?JedisPoolConfig(); ????????????//連接耗盡時是否阻塞,?false報異常,ture阻塞直到超時,?默認true ????????????config.setBlockWhenExhausted(true); ????????????//設置的逐出策略類名,?默認DefaultEvictionPolicy(當連接超過最大空閑時間,或連接數超過最大空閑連接數) ????????????config.setEvictionPolicyClassName("org.apache.commons.pool2.impl.DefaultEvictionPolicy"); ????????????//是否啟用pool的jmx管理功能,?默認true ????????????config.setJmxEnabled(true); ????????????//MBean?ObjectName?=?new?ObjectName("org.apache.commons.pool2:type=GenericObjectPool,name="?+?"pool"?+?i);?默認為"pool",?JMX不熟,具體不知道是干啥的...默認就好. ????????????config.setJmxNamePrefix("pool"); ????????????//是否啟用后進先出,?默認true ????????????config.setLifo(true); ????????????//最大空閑連接數,?默認8個 ????????????config.setMaxIdle(8); ????????????//最大連接數,?默認8個 ????????????config.setMaxTotal(8); ????????????//獲取連接時的最大等待毫秒數(如果設置為阻塞時BlockWhenExhausted),如果超時就拋異常,?小于零:阻塞不確定的時間,??默認-1 ????????????config.setMaxWaitMillis(-1); ????????????//逐出連接的最小空閑時間?默認1800000毫秒(30分鐘) ????????????config.setMinEvictableIdleTimeMillis(1800000); ????????????//最小空閑連接數,?默認0 ????????????config.setMinIdle(0); ????????????//每次逐出檢查時?逐出的最大數目?如果為負數就是?:?1/abs(n),?默認3 ????????????config.setNumTestsPerEvictionRun(3); ????????????//對象空閑多久后逐出,?當空閑時間>該值?且?空閑連接>最大空閑數?時直接逐出,不再根據MinEvictableIdleTimeMillis判斷??(默認逐出策略) ????????????config.setSoftMinEvictableIdleTimeMillis(1800000); ????????????//在獲取連接的時候檢查有效性,?默認false ????????????config.setTestOnBorrow(false); ????????????//在空閑時檢查有效性,?默認false ????????????config.setTestWhileIdle(false); ????????????//逐出掃描的時間間隔(毫秒)?如果為負數,則不運行逐出線程,?默認-1 ????????????config.setTimeBetweenEvictionRunsMillis(-1); ????????????jedisPool?=?new?JedisPool(config,?addr,?port,?3000,?auth); ????????}?catch?(Exception?e)?{ ????????????e.printStackTrace(); ????????} ????} ????/** ?????*?獲取?Jedis?資源 ?????*?@return ?????*/ ????public?static?Jedis?getJedis()?{ ????????if?(jedisPool?!=?null)?{ ????????????return?jedisPool.getResource(); ????????} ????????return?null; ????} ????/** ?????*?釋放Jedis資源 ?????*/ ????public?static?void?close(final?Jedis?jedis)?{ ????????if?(jedis?!=?null)?{ ????????????jedis.close(); ????????} ????} }
簡單測試
public?static?void?main(String[]?args)?throws?InterruptedException?{ ????//獲取?jedis?客戶端 ????Jedis?jedis?=?RedisPoolUtils.getJedis(); ????System.out.println("清空數據:"+jedis.flushDB()); ????System.out.println("判斷某個鍵是否存在:"+jedis.exists("username")); ????System.out.println("新增<'username','xmr'>的鍵值對:"+jedis.set("username",?"xmr")); ????System.out.println(jedis.exists("username")); ????System.out.println("新增<'password','password'>的鍵值對:"+jedis.set("password",?"123")); ????System.out.print("系統中所有的鍵如下:"); ????Set<String>?keys?=?jedis.keys("*"); ????System.out.println(keys); ????System.out.println("刪除鍵password:"+jedis.del("password")); ????System.out.println("判斷鍵password是否存在:"+jedis.exists("password")); ????System.out.println("設置鍵username的過期時間為5s:"+jedis.expire("username",?8L)); ????TimeUnit.SECONDS.sleep(1); ????System.out.println("查看鍵username的剩余生存時間:"+jedis.ttl("username")); ????System.out.println("移除鍵username的生存時間:"+jedis.persist("username")); ????System.out.println("查看鍵username的剩余生存時間:"+jedis.ttl("username")); ????System.out.println("查看鍵username所存儲的值的類型:"+jedis.type("username")); ????RedisPoolUtils.close(jedis); }
運行結果如下:
清空數據:OK
判斷某個鍵是否存在:false
新增<'username','xmr'>的鍵值對:OK
true
新增<'password','password'>的鍵值對:OK
系統中所有的鍵如下:[password,?username]
刪除鍵password:1
判斷鍵password是否存在:false
設置鍵username的過期時間為5s:1
查看鍵username的剩余生存時間:7
移除鍵username的生存時間:1
查看鍵username的剩余生存時間:-1
查看鍵username所存儲的值的類型:string
2.4、字符串常用 API 操作
public?class?RedisClientUtil?{ ????private?static?final?Logger?log?=?LoggerFactory.getLogger(RedisClientUtil.class); ????/** ?????*?獲取指定key的值,如果key不存在返回null ?????*?返回值:返回?key?的值,如果?key?不存在時,返回?nil ?????*?@param?key ?????*?@return ?????*/ ????public?static?String?get(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.get(key); ????????}?catch?(Exception?e){ ????????????log.error("get命令操作失敗,請求參數:{}",?key,e); ????????} ????????return?null; ????} ????/** ?????*?設置key的值為value ?????*?返回值:操作成功完成時返回?OK ?????*?@param?key ?????*?@return ?????*/ ????public?static?String?set(String?key,?String?value)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.set(key,?value); ????????}?catch?(Exception?e){ ????????????log.error("set命令操作失敗,參數key:{},參數value:{}",?key,?value,e); ????????} ????????return?null; ????} ????/** ?????*?刪除指定的key,返回值:被刪除?key?的數量 ?????*?返回值:被刪除?key?的數量 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?del(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????Long?result?=?jedis.del(key); ????????????return?jedis.del(key); ????????}?catch?(Exception?e){ ????????????log.error("del命令操作失敗,參數key:{}",?key,e); ????????} ????????return?0L; ????} ????/** ?????*?通過key向指定的value值追加值 ?????*?返回值:追加指定值之后,?key中字符串的長度 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?append(String?key,?String?value)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.append(key,?value); ????????}?catch?(Exception?e){ ????????????log.error("append命令操作失敗,參數key:{},參數value:{}",?key,?value,e); ????????} ????????return?0L; ????} ????/** ?????*?判斷key是否存在 ?????*?返回值:true/false ?????*?@param?key ?????*?@return ?????*/ ????public?static?Boolean?exists(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.exists(key); ????????}?catch?(Exception?e){ ????????????log.error("exists命令操作失敗,參數key:{}",?key,e); ????????} ????????return?false; ????} ????/** ?????*?設置key的超時時間為seconds ?????*?返回值:若?key?存在返回?1?,否則返回?0 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?expire(String?key,?long?seconds)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.expire(key,?seconds); ????????}?catch?(Exception?e){ ????????????log.error("expire命令操作失敗,參數key:{},參數seconds:{}",?key,?seconds,e); ????????} ????????return?0L; ????} ????/** ?????*?返回?key?的剩余過期時間(單位秒) ?????*?返回值:當?key?不存在時,返回?-2?。?當?key?存在但沒有設置剩余生存時間時,返回?-1?。?否則,以秒為單位,返回?key?的剩余生存時間 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?ttl(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.ttl(key); ????????}?catch?(Exception?e){ ????????????log.error("ttl命令操作失敗,參數key:{}",?key,e); ????????} ????????return?0L; ????} ????/** ?????*?設置指定key的值為value,當key不存在時才設置 ?????*?返回值:設置成功返回?1,設置失敗返回?0 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?setnx(String?key,?String?value)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.setnx(key,?value); ????????}?catch?(Exception?e){ ????????????log.error("setnx命令操作失敗,參數key:{},參數value:{}",?key,?value,e); ????????} ????????return?0L; ????} ????/** ?????*?設置指定key的值為value,并設置過期時間 ?????*?返回值:設置成功時返回?OK ?????*?@param?key ?????*?@return ?????*/ ????public?static?String?setex(String?key,?String?value,?long?seconds)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.setex(key,?seconds,?value); ????????}?catch?(Exception?e){ ????????????log.error("setex命令操作失敗,參數key:{},參數value:{}",?key,?value,e); ????????} ????????return?null; ????} ????/** ?????*?通過key?和offset?從指定的位置開始將原先value替換 ?????*?返回值:被修改后的字符串長度 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?setrange(String?key,?int?offset,?String?value)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.setrange(key,?offset,?value); ????????}?catch?(Exception?e){ ????????????log.error("setrange命令操作失敗,參數key:{},參數value:{},參數offset:{}",?key,?value,?offset,e); ????????} ????????return?null; ????} ????/** ?????*?通過批量的key獲取批量的value ?????*?返回值:一個包含所有給定?key?的值的列表。 ?????*?@param?keys ?????*?@return ?????*/ ????public?static?List<String>?mget(String...?keys)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.mget(keys); ????????}?catch?(Exception?e){ ????????????log.error("mget命令操作失敗,參數key:{}",?keys.toString(),e); ????????} ????????return?null; ????} ????/** ?????*?批量的設置key:value,也可以一個 ?????*?返回值:總是返回?OK ?????*?@param?keysValues ?????*?@return ?????*/ ????public?static?String?mset(String...?keysValues)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.mset(keysValues); ????????}?catch?(Exception?e){ ????????????log.error("mset命令操作失敗,參數key:{}",?keysValues.toString(),e); ????????} ????????return?null; ????} ????/** ?????*?設置key的值,并返回一個舊值 ?????*?返回值:返回給定?key?的舊值,當?key?沒有舊值時,即?key?不存在時,返回?nil ?????*?@param?key ?????*?@return ?????*/ ????public?static?String?getSet(String?key,?String?value)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.getSet(key,?value); ????????}?catch?(Exception?e){ ????????????log.error("getSet命令操作失敗,參數key:{},參數value:{}",?key,?value,e); ????????} ????????return?null; ????} ????/** ?????*?通過下標和?key?獲取指定下標位置的?value ?????*?返回值:截取得到的子字符串 ?????*?@param?key ?????*?@return ?????*/ ????public?static?String?getrange(String?key,?int?startOffset,?int?endOffset)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.getrange(key,?startOffset,?endOffset); ????????}?catch?(Exception?e){ ????????????log.error("getrange命令操作失敗,參數key:{},參數startOffset:{},參數offset:{}",?key,?startOffset,?endOffset,e); ????????} ????????return?null; ????} ????/** ?????*?通過key?對value進行加值+1操作,當value不是int類型時會返回錯誤,當key不存在是則value為1 ?????*?返回值:執行INCR命令之后?key?的值 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?incr(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.incr(key); ????????}?catch?(Exception?e){ ????????????log.error("incr命令操作失敗,參數key:{}",?key,?e); ????????} ????????return?0L; ????} ????/** ?????*?通過key給指定的value加值 ?????*?返回值:執行INCR命令之后?key?的值 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?incrBy(String?key,?long?increment)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.incrBy(key,?increment); ????????}?catch?(Exception?e){ ????????????log.error("incrBy命令操作失敗,參數key:{},參數increment:{}",?key,?increment,e); ????????} ????????return?0L; ????} ????/** ?????*?對key的值做減減操作 ?????*?返回值:執行INCR命令之后?key?的值 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?decr(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.decr(key); ????????}?catch?(Exception?e){ ????????????log.error("decr命令操作失敗,參數key:{}",?key,?e); ????????} ????????return?0L; ????} ????/** ?????*?對key的值做減減操作,減去指定的值 ?????*?返回值:執行INCR命令之后?key?的值 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?decrBy(String?key,?long?decrement)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.decrBy(key,?decrement); ????????}?catch?(Exception?e){ ????????????log.error("decrBy命令操作失敗,參數key:{},參數decrement:{}",?key,?decrement,e); ????????} ????????return?0L; ????} ????/** ?????*?通過key獲取value值的長度 ?????*?返回值:value值的長度 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?strlen(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.strlen(key); ????????}?catch?(Exception?e){ ????????????log.error("strlen命令操作失敗,參數key:{}",?key,?e); ????????} ????????return?0L; ????} }
2.5、哈希常用 API 操作
public?class?RedisClientUtil?{ ????private?static?final?Logger?log?=?LoggerFactory.getLogger(RedisClientUtil.class); ????/** ?????*?通過key?和?field?獲取指定的?value ?????*?返回值:對應的value值 ?????*?@param?key ?????*?@return ?????*/ ????public?static?String?hget(String?key,?String?field)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.hget(key,?field); ????????}?catch?(Exception?e){ ????????????log.error("hget命令操作失敗,參數key:{},參數field:{}",?key,?field,e); ????????} ????????return?null; ????} ????/** ?????*?通過key給field設置指定的值,如果key不存在,則先創建 ?????*?返回值:如果字段是哈希表中的一個新建字段,并且值設置成功,返回?1?;如果哈希表中域字段已經存在且舊值已被新值覆蓋,返回?0?。 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?hset(String?key,?String?field,?String?value)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.hset(key,?field,?value); ????????}?catch?(Exception?e){ ????????????log.error("hset命令操作失敗,參數key:{},參數field:{},參數value:{}",?key,?field,?value,e); ????????} ????????return?0L; ????} ????/** ?????*?通過key和field判斷是否有指定的value存在 ?????*?返回值:true/false ?????*?@param?key ?????*?@return ?????*/ ????public?static?Boolean?hexists(String?key,?String?field)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.hexists(key,?field); ????????}?catch?(Exception?e){ ????????????log.error("hexists命令操作失敗,參數key:{},參數field:{}",?key,?field,e); ????????} ????????return?false; ????} ????/** ?????*?通過key返回field的數量 ?????*?返回值:field的數量 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?hlen(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.hlen(key); ????????}?catch?(Exception?e){ ????????????log.error("hlen命令操作失敗,參數key:{}",?key,e); ????????} ????????return?0L; ????} ????/** ?????*?通過key?刪除指定的?field ?????*?返回值:刪除的數量 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?hdel(String?key,?String...?fields)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.hdel(key,?fields); ????????}?catch?(Exception?e){ ????????????log.error("hdel命令操作失敗,參數key:{},參數fields:{}",?key,?fields.toString(),e); ????????} ????????return?0L; ????} ????/** ?????*?通過key返回所有的field ?????*?返回值:field集合 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Set<String>?hkeys(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.hkeys(key); ????????}?catch?(Exception?e){ ????????????log.error("hkeys命令操作失敗,參數key:{}",?key,e); ????????} ????????return?null; ????} ????/** ?????*?通過key獲取所有的field和value ?????*?返回值:map對象 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Map<String,?String>?hgetAll(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.hgetAll(key); ????????}?catch?(Exception?e){ ????????????log.error("hgetAll命令操作失敗,參數key:{}",?key,e); ????????} ????????return?null; ????} }
2.6、列表常用 API 操作
public?class?RedisClientUtil?{ ????private?static?final?Logger?log?=?LoggerFactory.getLogger(RedisClientUtil.class); ????/** ?????*?過key向list頭部添加字符串 ?????*?返回值:執行?LPUSH?命令后,列表的長度 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?lpush(String?key,?String...?strs)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.lpush(key,?strs); ????????}?catch?(Exception?e){ ????????????log.error("lpush命令操作失敗,參數key:{},參數strs:{}",?key,?strs.toString(),e); ????????} ????????return?null; ????} ????/** ?????*?通過key向list尾部添加字符串 ?????*?返回值:執行?RPUSH?命令后,列表的長度 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?rpush(String?key,?String...?strs)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.rpush(key,?strs); ????????}?catch?(Exception?e){ ????????????log.error("rpush命令操作失敗,參數key:{},參數strs:{}",?key,?strs.toString(),e); ????????} ????????return?null; ????} ????/** ?????*?通過key設置list指定下標位置的value?如果下標超過list里面value的個數則報錯 ?????*?返回值:操作成功返回?ok?,否則返回錯誤信息 ?????*?@param?key ?????*?@return ?????*/ ????public?static?String?lset(String?key,?Long?index,?String?value)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.lset(key,?index,?value); ????????}?catch?(Exception?e){ ????????????log.error("lset命令操作失敗,參數key:{},參數index:{},參數value:{}",?key,?index,?value,e); ????????} ????????return?null; ????} ????/** ?????*?通過key從對應的list中刪除指定的count個?和?value相同的元素 ?????*?返回值:返回被刪除的個數 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?lrem(String?key,?long?count,?String?value)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.lrem(key,?count,?value); ????????}?catch?(Exception?e){ ????????????log.error("lrem命令操作失敗,參數key:{},參數count:{},參數value:{}",?key,?count,?value,e); ????????} ????????return?null; ????} ????/** ?????*?通過key保留list中從strat下標開始到end下標結束的value值 ?????*?返回值:操作成功返回?ok?,否則返回錯誤信息 ?????*?@param?key ?????*?@return ?????*/ ????public?static?String?ltrim(String?key,?long?start,?long?end)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.ltrim(key,?start,?end); ????????}?catch?(Exception?e){ ????????????log.error("ltrim命令操作失敗,參數key:{},參數start:{},參數end:{}",?key,?start,?end,e); ????????} ????????return?null; ????} ????/** ?????*?通過key從list的頭部刪除一個value,并返回該value ?????*?返回值:value值 ?????*?@param?key ?????*?@return ?????*/ ????public?static?String?lpop(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.lpop(key); ????????}?catch?(Exception?e){ ????????????log.error("lpop命令操作失敗,參數key:{}",?key,e); ????????} ????????return?null; ????} ????/** ?????*?通過key從list尾部刪除一個value,并返回該元素 ?????*?返回值:value值 ?????*?@param?key ?????*?@return ?????*/ ????public?static?String?rpop(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.rpop(key); ????????}?catch?(Exception?e){ ????????????log.error("rpop命令操作失敗,參數key:{}",?key,e); ????????} ????????return?null; ????} ????/** ?????*?通過key獲取list中指定下標位置的value ?????*?返回值:value值 ?????*?@param?key ?????*?@return ?????*/ ????public?static?String?lindex(String?key,?long?index){ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.lindex(key,?index); ????????}?catch?(Exception?e){ ????????????log.error("lindex命令操作失敗,參數key:{},參數index:{}",?key,?index,e); ????????} ????????return?null; ????} ????/** ?????*?通過key返回list的長度 ?????*?返回值:value值 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?llen(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.llen(key); ????????}?catch?(Exception?e){ ????????????log.error("llen命令操作失敗,參數key:{}",?key,e); ????????} ????????return?null; ????} ????/** ?????*?通過key獲取list指定下標位置的value?如果start?為?0?end?為?-1?則返回全部的list中的value ?????*?返回值:value值 ?????*?@param?key ?????*?@return ?????*/ ????public?static?List<String>?lrange(String?key,?long?start,?long?end)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.lrange(key,?start,?end); ????????}?catch?(Exception?e){ ????????????log.error("lrange命令操作失敗,參數key:{},參數start:{},參數end:{}",?key,?start,?end,e); ????????} ????????return?null; ????} }
2.7、集合常用 API 操作
public?class?RedisClientUtil?{ ????private?static?final?Logger?log?=?LoggerFactory.getLogger(RedisClientUtil.class); ????/** ?????*?通過key向指定的set中添加value ?????*?返回值:添加成功的個數 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?sadd(String?key,?String...?members)??{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.sadd(key,?members); ????????}?catch?(Exception?e){ ????????????log.error("sadd命令操作失敗,參數key:{},參數members:{}",?key,?members.toString(),e); ????????} ????????return?null; ????} ????/** ?????*?通過key刪除set中對應的value值 ?????*?返回值:刪除成功的個數 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?srem(String?key,?String...?members)??{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.srem(key,?members); ????????}?catch?(Exception?e){ ????????????log.error("srem命令操作失敗,參數key:{},參數members:{}",?key,?members.toString(),e); ????????} ????????return?null; ????} ????/** ?????*?通過key獲取set中value的個數 ?????*?返回值:value的個數 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?scard(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.scard(key); ????????}?catch?(Exception?e){ ????????????log.error("scard命令操作失敗,參數key:{}",?key,e); ????????} ????????return?0L; ????} ????/** ?????*?通過key判斷value是否是set中的元素 ?????*?返回值:true/false ?????*?@param?key ?????*?@return ?????*/ ????public?static?Boolean?sismember(String?key,?String?member)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.sismember(key,?member); ????????}?catch?(Exception?e){ ????????????log.error("sismember命令操作失敗,參數key:{},參數member:{}",?key,?member,e); ????????} ????????return?false; ????} ????/** ?????*?通過key獲取set中所有的value ?????*?返回值:所有的value ?????*?@param?key ?????*?@return ?????*/ ????public?static?Set<String>?smembers(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.smembers(key); ????????}?catch?(Exception?e){ ????????????log.error("smembers命令操作失敗,參數key:{}",?key,e); ????????} ????????return?null; ????} }
2.8、有序集合常用 API 操作
public?class?RedisClientUtil?{ ????private?static?final?Logger?log?=?LoggerFactory.getLogger(RedisClientUtil.class); ????/** ?????*?通過key向zset中添加value,score,其中score就是用來排序的?如果該value已經存在則根據score更新元素 ?????*?返回值:被成功添加的新成員的數量,不包括那些被更新的、已經存在的成員 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?zadd(String?key,?double?score,?String?member)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.zadd(key,?score,?member); ????????}?catch?(Exception?e){ ????????????log.error("zadd命令操作失敗,參數key:{},參數score:{},參數member:{}",?key,?score,?member,e); ????????} ????????return?null; ????} ????/** ?????*?通過key刪除在zset中指定的value ?????*?返回值:刪除個數 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?zrem(String?key,?String...?members)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.zrem(key,?members); ????????}?catch?(Exception?e){ ????????????log.error("zrem命令操作失敗,參數key:{},參數members:{}",?key,?members.toString(),e); ????????} ????????return?null; ????} ????/** ?????*?通過key增加該zset中value的score的值 ?????*?返回值:member?成員的新分數值 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Double?zincrby(String?key,?double?score,?String?member)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.zincrby(key,?score,?member); ????????}?catch?(Exception?e){ ????????????log.error("zincrby命令操作失敗,參數key:{},參數score:{},參數member:{}",?key,?score,?member,e); ????????} ????????return?null; ????} ????/** ?????*?通過key返回zset中value的排名?下標從小到大排序 ?????*?返回值:返回?member?的排名 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?zrank(String?key,?String?member)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.zrank(key,?member); ????????}?catch?(Exception?e){ ????????????log.error("zrank命令操作失敗,參數key:{},參數member:{}",?key,?member,e); ????????} ????????return?null; ????} ????/** ?????*?通過key將獲取score從start到end中zset的value?socre從大到小排序?當start為0?end為-1時返回全部 ?????*?返回值:返回?member?集合 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Set<String>?zrevrange(String?key,?long?start,?long?end)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.zrevrange(key,?start,?end); ????????}?catch?(Exception?e){ ????????????log.error("zrevrange命令操作失敗,參數key:{},參數start:{},參數end:{}",?key,?start,?end,e); ????????} ????????return?null; ????} ????/** ?????*?返回指定區間內zset中value的數量 ?????*?返回值:返回?member?集合 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?zcount(String?key,?String?min,?String?max)??{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.zcount(key,?min,?max); ????????}?catch?(Exception?e){ ????????????log.error("zcount命令操作失敗,參數key:{},參數min:{},參數max:{}",?key,?min,?max,e); ????????} ????????return?null; ????} ????/** ?????*?通過key返回zset中的value個數 ?????*?返回值:返回?member?集合 ?????*?@param?key ?????*?@return ?????*/ ????public?static?Long?zcard(String?key)??{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.zcard(key); ????????}?catch?(Exception?e){ ????????????log.error("zcard命令操作失敗,參數key:{}",?key,e); ????????} ????????return?null; ????} ????/** ?????*?返回滿足pattern表達式的所有key?keys(*)?返回所有的key ?????*?返回值:返回?key?集合 ?????*?@param?pattern ?????*?@return ?????*/ ????public?static?Set<String>?keys(String?pattern)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.keys(pattern); ????????}?catch?(Exception?e){ ????????????log.error("keys命令操作失敗,參數pattern:{}",?pattern,e); ????????} ????????return?null; ????} ????/** ?????*?通過key判斷值得類型 ?????*?返回值:值的類型 ?????*?@param?key ?????*?@return ?????*/ ????public?static?String?type(String?key)?{ ????????try?(Jedis?jedis?=?jedisPool.getResource())?{ ????????????return?jedis.type(key); ????????}?catch?(Exception?e){ ????????????log.error("type命令操作失敗,參數key:{}",?key,e); ????????} ????????return?null; ????} }
三、集群配置
在實際的項目生產環境中,redis 通常不是以單臺服務實例來運行的,因為一旦服務器掛了,可能所有的下游服務都會受到影響,因此為了保障單臺服務器即使出現故障也能運行,通常運維組會搭建集群環境,來保證服務高可用。
搭建的方式有兩種,哨兵模式和 Cluster 模式。
- 哨兵模式:對redis服務器進行監控,如果有宕機的,就從備機里面選一個出來作為主機,實現自動切換
- Cluster 模式:將數據進行分片存儲,避免全部節點數據都一樣,浪費空間
3.1、哨兵模式
哨兵模式簡單的說,就是一臺主機,一臺備機,外加一臺監控服務,當監控服務觀測到主機已經宕機,就會將備用機切換成主機,以便繼續提供服務。
public?class?RedisPoolUtils?{ ????private?static?Jedis?jedis; ????private?static?JedisSentinelPool?jedisSentinelPool; ????static{ ????????try?{ ????????????JedisPoolConfig?config?=?new?JedisPoolConfig(); ????????????//最大空閑連接數,?默認8個 ????????????config.setMaxIdle(8); ????????????//最大連接數,?默認8個 ????????????config.setMaxTotal(8); ????????????//最小空閑連接數,?默認0 ????????????config.setMinIdle(0); ????????????//獲取連接時的最大等待毫秒數(如果設置為阻塞時BlockWhenExhausted),如果超時就拋異常,?小于零:阻塞不確定的時間,??默認-1 ????????????config.setMaxWaitMillis(3000); ????????????//在獲取連接的時候檢查有效性,表示取出的redis對象可用,?默認false ????????????config.setTestOnBorrow(true); ????????????//redis服務器列表 ????????????Set<String>?sentinels?=?new?HashSet<>(); ????????????sentinels.add(new?HostAndPort("192.168.43.212",?26379).toString()); ????????????sentinels.add(new?HostAndPort("192.168.43.213",?26379).toString()); ????????????sentinels.add(new?HostAndPort("192.168.43.214",?26379).toString()); ????????????//初始化連接池 ????????????jedisSentinelPool?=?new?JedisSentinelPool("mymaster",?sentinels,?config,?"111111"); ????????????//?從池中獲取一個Jedis對象 ????????????jedis?=?jedisSentinelPool.getResource(); ????????}?catch?(Exception?e)?{ ????????????e.printStackTrace(); ????????} ????} ???? }
3.2、集群模式
為了保證高可用,redis-cluster集群通常會引入主從復制模型,一個主節點對應一個或者多個從節點,當主節點宕機的時候,就會啟用從節點。
public?class?RedisPoolUtils?{ ????static{ ????????try?{ ????????????JedisPoolConfig?config?=?new?JedisPoolConfig(); ????????????//最大空閑連接數,?默認8個 ????????????config.setMaxIdle(8); ????????????//最大連接數,?默認8個 ????????????config.setMaxTotal(8); ????????????//最小空閑連接數,?默認0 ????????????config.setMinIdle(0); ????????????//獲取連接時的最大等待毫秒數(如果設置為阻塞時BlockWhenExhausted),如果超時就拋異常,?小于零:阻塞不確定的時間,??默認-1 ????????????config.setMaxWaitMillis(3000); ????????????//在獲取連接的時候檢查有效性,表示取出的redis對象可用,?默認false ????????????config.setTestOnBorrow(true); ????????????Set<HostAndPort>?nodes?=?new?HashSet<>(); ????????????nodes.add(new?HostAndPort("192.168.43.212",?26379)); ????????????nodes.add(new?HostAndPort("192.168.43.213",?26379)); ????????????nodes.add(new?HostAndPort("192.168.43.214",?26379)); ????????????JedisCluster?jedisCluster?=?new?JedisCluster(nodes,?config); ????????????jedisCluster.set("key",?"hello?world"); ????????????jedisCluster.close(); ????????}?catch?(Exception?e)?{ ????????????e.printStackTrace(); ????????} ????} }
四、小結
jedis
客戶端是目前使用最廣泛的一款 java 客戶端,也是老牌的 Redis 的 Java 實現客戶端。
優點很突出:
- 比較全面的提供了 Redis 的操作特性,也就是說你能用 redis 命令操作的,Jedis 包都也給你封裝好了,直接使用即可
- 使用廣泛,易上手
當然,缺點也有:
- Jedis 客戶端實例不是線程安全的,需要借助連接池來管理和使用 Jedis
- 使用阻塞的I/O,且其方法調用都是同步的,程序流需要等到 sockets 處理完 I/O 才能執行,不支持異步
原文鏈接:https://mp.weixin.qq.com/s/XRRmiWXEgpKmf04Rp48l_Q
相關推薦
- 2022-12-04 React使用refs操作DOM方法詳解_React
- 2022-03-29 python教程之生成器和匿名函數_python
- 2022-08-12 Go單元測試對GORM進行Mock測試_Golang
- 2023-07-05 cnpm安裝appium出現cannot find module xxx
- 2024-07-13 根據腳手架archetype快速構建spring boot/cloud項目
- 2024-03-10 詳解Spring Bean的生命周期
- 2022-04-30 DataGridView凍結列或行、列順序調整、操作行頭列頭標題的方法_C#教程
- 2022-08-10 詳細聊一聊algorithm中的排序算法_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支