1隶症、Redis相關(guān)網(wǎng)址
Redis 官網(wǎng):https://redis.io/
Redis 命令參考:http://doc.redisfans.com/
2、Redis優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
? ? ????1风响、性能極高?– Redis能讀的速度是110000次/s,寫的速度是81000次/s 清钥。
? ????? 2艺谆、豐富的數(shù)據(jù)類型 – Redis支持 Strings, Lists, Hashes, Sets 及 Ordered Sets 數(shù)據(jù)類型操作弊决,以及Bitmaps、HyperLogLogs擅威、GEO(坐標(biāo))
? ????? 3壕探、原子 – Redis的所有操作都是原子性的,意思就是要么成功執(zhí)行要么失敗完全不執(zhí)行郊丛。單個操作是原子性的李请。多個操作也支持事務(wù)瞧筛,即原子性,通過MULTI和EXEC指令包起來导盅。
? ????? 4较幌、豐富的特性?– Redis還支持 publish/subscribe, 通知, key 過期等等特性。
缺點(diǎn)
? ? ????1白翻、數(shù)據(jù)庫容量受到物理內(nèi)存的限制乍炉,不能用作海量數(shù)據(jù)的高性能讀寫,因此Redis適合的場景主要局限在較小數(shù)據(jù)量的高性能操作和運(yùn)算上滤馍。
? ????? 2岛琼、Redis 不具備自動容錯和恢復(fù)功能,主機(jī)從機(jī)的宕機(jī)都會導(dǎo)致前端部分讀寫請求失敗纪蜒,需要等待機(jī)器重啟或者手動切換前端的IP才能恢復(fù)衷恭。
? ? ????3此叠、主機(jī)宕機(jī)纯续,宕機(jī)前有部分?jǐn)?shù)據(jù)未能及時同步到從機(jī),切換IP后還會引入數(shù)據(jù)不一致的問題灭袁,降低了系統(tǒng)的可用性猬错。
3、Redis為什么這么快
????????1茸歧、完全基于內(nèi)存倦炒,絕大部分請求是純粹的內(nèi)存操作,非橙硐梗快速逢唤。數(shù)據(jù)存在內(nèi)存中,類似于 HashMap涤浇,查找和操作的時間復(fù)雜度都是O(1)鳖藕;
????????2、使用多路 I/O 復(fù)用模型只锭,非阻塞 IO著恩;
????????3、采用單線程蜻展,避免了不必要的上下文切換和競爭條件喉誊,也不存在多進(jìn)程或者多線程導(dǎo)致的切換而消耗 CPU,不用去考慮各種鎖的問題纵顾,不存在加鎖釋放鎖操作伍茄,不會出現(xiàn)死鎖而導(dǎo)致的性能消耗;(Redis4.0之后并不是單線程施逾,除了主線程外敷矫,它也有后臺線程在處理一些較為緩慢的操作贞盯,例如清理臟數(shù)據(jù)、無用連接的釋放沪饺、大 key 的刪除等等)
????????4躏敢、數(shù)據(jù)結(jié)構(gòu)簡單,對數(shù)據(jù)操作也簡單整葡,Redis 中的數(shù)據(jù)結(jié)構(gòu)是專門進(jìn)行設(shè)計(jì)的件余;
4、Redis主要數(shù)據(jù)類型及其應(yīng)用場景
????????Redis支持的常用5種數(shù)據(jù)類型分別為:字符串String遭居、列表List啼器、哈希Hash、集合Set俱萍、有序集合Zset
????????Redis底層的數(shù)據(jù)結(jié)構(gòu)包括:簡單動態(tài)數(shù)組SDS端壳、鏈表、字典枪蘑、跳躍鏈表损谦、整數(shù)集合、壓縮列表(為節(jié)約內(nèi)存而開發(fā)的經(jīng)過特殊編碼之后的連續(xù)內(nèi)存塊順序型數(shù)據(jù)結(jié)構(gòu))岳颇、對象照捡。Redis為了平衡空間和時間效率,針對value的具體類型在底層會采用不同的數(shù)據(jù)結(jié)構(gòu)來實(shí)現(xiàn)话侧,其中哈希表和壓縮列表是復(fù)用比較多的數(shù)據(jù)結(jié)構(gòu)栗精,如下圖展示了對外數(shù)據(jù)類型和底層數(shù)據(jù)結(jié)構(gòu)之間的映射關(guān)系:
①string
????????String 是 Redis 最基本的類型,即一個 Key 對應(yīng)一個 Value瞻鹏。Value 不僅可以是 String悲立,也可以是數(shù)字。而且String 類型是二進(jìn)制安全的新博,意思是 Redis 的 String 類型可以包含任何數(shù)據(jù)薪夕,比如 jpg 圖片或者序列化的對象。String 類型的值最大能存儲 512M叭披。
常用命令:get寥殖、set、incr涩蜘、decr嚼贡、mget等。
使用場景:常規(guī)key-value緩存應(yīng)用同诫。計(jì)數(shù)器粤策、緩存、分布式序列號误窖、分布式鎖等等叮盘。
示例:
1秩贰、單值緩存
????????set key value
????????get key
2、對象緩存
????????1)set user:1 value(json 格式數(shù)據(jù))
????????2)mset user:1name xxx user:1:balance 1222
????????????mget user:1:name user:1:balance
3柔吼、分布式鎖
????????setnx product:10001 true //返回1表示獲取鎖成功
????????setnx product:10001 true //返回0表示獲取鎖失敗
????????del product:10001 //釋放鎖
????????set product:10001 true ex 10 nx //防止程序意外終止導(dǎo)致死鎖
4毒费、計(jì)數(shù)器(閱讀數(shù)實(shí)現(xiàn))
????????incr article:readcount:{文章id} //自增+1
????????get article:readcount:{文章id}
5、web集群session共享
????????Spring session +redis實(shí)現(xiàn)session共享?
6愈魏、分布式系統(tǒng)全局序列號
????????incrby orderId 1000? //redis 批量生成序列號提升性能
②hash
????????hash?是一個鍵值(key? value)對集合觅玻。是一個 string 類型的 field 和 value 的映射表,hash 特別適合用于存儲對象培漏。
常用命令:hget,hset,hgetall 等溪厘。
應(yīng)用場景:存儲部分變更數(shù)據(jù),如用戶信息等牌柄,獲取/修改用戶對象某一屬性比較方便畸悬。
示例:
1、用戶對象緩存
????????hmset user {userid}:name yoyoshaly? {userid}:balance 1111
????????hmget user {userid}:name? {userid}:balance
2珊佣、電商購物車
????????1)以用戶id為key
????????2)商品id為filed
????????3)商品數(shù)量為value
????????購物車具體操作
????????1)添加商品 -》hset cart:1001 10088 1
????????2)增加購物車 -〉hincrby cart:1001 10088 1 //hincrby cart:uid pid x? x增加數(shù)量
????????3)商品總數(shù)-》hlen cart:1001
????????4)刪除商品-〉hdel cart:1001 10088
????????5)獲取購物車所有商品-》hgetall cart:1001
③list
????????List 類似是一個雙向鏈表蹋宦,既可以支持反向查找和遍歷,更方便操作彩扔。
常用命令:
????????1)lpush(添加左邊元素),rpush,
????????2)lpop(移除左邊第一個元素),rpop,
????????3)lrange(獲取列表片段 LRANGE key start stop,
????????4)stack(棧實(shí)現(xiàn))LPUSH+LPOP->FILO ,
????????5)queue(隊(duì)列實(shí)現(xiàn))LPUSH+RPOP? ,
????????6)blocking mq(阻塞隊(duì)列)LPUSH+BRPOP .? //BRPOP 從key列表的表尾(right)彈出一個元素妆档,若隊(duì)列中沒有元素僻爽,阻塞等待timeout秒虫碉,如果timeout=0,一直阻塞等待胸梆。
應(yīng)用場景:List 應(yīng)用場景非常多敦捧,也是 Redis 最重要的數(shù)據(jù)結(jié)構(gòu)之一,比如 關(guān)注列表碰镜,粉絲列表兢卵,還可以實(shí)現(xiàn)隊(duì)列。
示例:
取最新N個數(shù)據(jù)的操作
????????1)登陸用戶放入隊(duì)列 -》 lpush login yoyo
????????2) 登陸用戶放入隊(duì)列 -》lpush login lily
????????3)登陸用戶放入隊(duì)列 -》lpush login shatt
????????4) 獲取前10個登陸用戶 -》lrange login 0 10
④set
????????Set 是 String 類型的無序集合绪颖。集合是通過 hashtable 實(shí)現(xiàn)的秽荤。Set 中的元素是沒有順序的,而且是沒有重復(fù)的柠横。而且 Set 提供了判斷某個成員是否在一個 Set 集合中窃款。
常用命令:sdd、spop牍氛、smembers晨继、sunion 等。
應(yīng)用場景:抽獎小功能搬俊、點(diǎn)贊紊扬、收藏蜒茄、共同好友,交集并集餐屎、差集等功能檀葛。
示例:
1、微信抽獎小程序
????????1)點(diǎn)擊參與抽獎加入集合
????????sadd key {userid}????
????????2)查看參與抽獎所有用戶
????????smembers key? //獲取集合key中所有元素
????????3)抽取count名中獎?wù)?/p>
????????srandmember key [count]? //從集合key中選出count個元素腹缩,元素不從key中刪除
????????或spop key [count]? //從集合key中選出count個元素驻谆,元素從key中刪除
2、微信微博點(diǎn)贊庆聘,收藏胜臊,標(biāo)簽
????????1)點(diǎn)贊
????????sadd like:{消息id} {用戶id}
????????2)取消點(diǎn)贊
????????srem like:{消息id} {用戶id} //從集合key中刪除元素
????????3)檢查用戶是否點(diǎn)過贊
????????sismember like:{消息id} {用戶id}
????????4)獲取點(diǎn)贊用戶列表
????????smembers like:{消息id}
????????5)獲取點(diǎn)贊用戶數(shù)
????????scard like:{消息id}
3、集合操作實(shí)現(xiàn)微信微博關(guān)注模型
????????set1 a,b,c
????????set2 b,c,d
????????set3 c,d,e
????????1)sinter set1 set2 set3 ->{c} 求交集
????????2)sunion set1 set2 set3 ->{a,b,c,d,e}求并集
????????3)sdiff 求差集 sdiff set1 set2 set3 ->{a} 以set1為基準(zhǔn) set1 -set2-set3
⑤sorted? set
????????Zset 和 Set 一樣是 String 類型元素的集合伙判,且不允許重復(fù)的元素象对。當(dāng)你需要一個有序的并且不重復(fù)的集合列表,那么可以選擇 Sorted Set 結(jié)構(gòu)宴抚。和 Set 相比勒魔,Sorted Set關(guān)聯(lián)了一個 Double 類型權(quán)重的參數(shù) Score,使得集合中的元素能夠按照 Score 進(jìn)行有序排列菇曲,Redis 正是通過分?jǐn)?shù)來為集合中的成員進(jìn)行從小到大的排序冠绢。Redis Sorted Set 的內(nèi)部使用 HashMap 和跳躍表(skipList)來保證數(shù)據(jù)的存儲和有序,HashMap 里放的是成員到 Score 的映射常潮。而跳躍表里存放的是所有的成員弟胀,排序依據(jù)是 HashMap 里存的 Score,使用跳躍表的結(jié)構(gòu)可以獲得比較高的查找效率喊式,并且在實(shí)現(xiàn)上比較簡單孵户。
常用命令:zadd、zrange岔留、zrem夏哭、zcard 等。
使用場景:Sorted Set 可以通過用戶額外提供一個優(yōu)先級(score)的參數(shù)來為成員排序献联,并且是插入有序的竖配,即自動排序。
示例:
返回有序成員列表
????????1)zadd runoob 0 redis
????????2)zadd runoob 0 mongodb
????????3)zadd runoob 0 rabitmq
????????4)zadd runoob 0 rabitmq
????????5) ZRANGEBYSCORE runoob 0 1000
????????????????"mongodb"
????????????????"rabitmq"
????????????????"redis"
數(shù)據(jù)類型應(yīng)用場景總結(jié):
5里逆、Redis線程模型
????????Redis基于Reactor模式開發(fā)了網(wǎng)絡(luò)事件處理器进胯,這個處理器被稱為文件事件處理器(file event handler)。它的組成結(jié)構(gòu)為4部分:多個套接字运悲、IO多路復(fù)用程序龄减、文件事件分派器、事件處理器班眯。因?yàn)槲募录峙善麝?duì)列的消費(fèi)是單線程的希停,所以Redis才叫單線程模型烁巫。
????????文件事件處理器使用 I/O 多路復(fù)用(multiplexing)程序來同時監(jiān)聽多個套接字, 并根據(jù)套接字目前執(zhí)行的任務(wù)來為套接字關(guān)聯(lián)不同的事件處理器宠能。
????????當(dāng)被監(jiān)聽的套接字準(zhǔn)備好執(zhí)行連接應(yīng)答(accept)亚隙、讀取(read)违崇、寫入(write)阿弃、關(guān)閉(close)等操作時, 與操作相對應(yīng)的文件事件就會產(chǎn)生羞延, 這時文件事件處理器就會調(diào)用套接字之前關(guān)聯(lián)好的事件處理器來處理這些事件渣淳。
????????雖然文件事件處理器以單線程方式運(yùn)行, 但通過使用 I/O 多路復(fù)用程序來監(jiān)聽多個套接字伴箩, 文件事件處理器既實(shí)現(xiàn)了高性能的網(wǎng)絡(luò)通信模型入愧, 又可以很好地與 redis 服務(wù)器中其他同樣以單線程方式運(yùn)行的模塊進(jìn)行對接, 這保持了 Redis 內(nèi)部單線程設(shè)計(jì)的簡單性嗤谚。
6棺蛛、淘汰策略以及內(nèi)存回收機(jī)制
????????redis作為內(nèi)存型數(shù)據(jù)庫,內(nèi)存不可能源源不斷的增加巩步。那么為了安全穩(wěn)定的運(yùn)行旁赊,內(nèi)存的使用率一定需要保持在一定合理的閾值范圍內(nèi)。合理的內(nèi)存回收機(jī)制也是很重要的椅野。內(nèi)存的占用主要是鍵值對存儲的消耗终畅,以及本身的運(yùn)行消耗。我們的回收主要指的是鍵值對的回收鳄橘。鍵值對可以分為幾種:帶過期的声离、不帶過期的、熱點(diǎn)數(shù)據(jù)瘫怜、冷數(shù)據(jù)。對于帶過期的鍵值是需要刪除的本刽,如果刪除了所有的過期鍵值對之后內(nèi)存仍然不足怎么辦鲸湃?那只能把部分?jǐn)?shù)據(jù)給踢掉了。
redis的內(nèi)存回收主要有:
1子寓、過期鍵刪除
刪除方式:
? ? ? ? 1暗挑、定時刪除(主動刪除):在設(shè)置鍵的過期時間的同時,創(chuàng)建定時器斜友,讓定時器在鍵過期時間到來時炸裆,即刻執(zhí)行鍵值對的刪除;此方式對內(nèi)存使用率有優(yōu)勢鲜屏,但是對CPU不友好
? ? ? ? 2烹看、定期刪除(主動刪除):每隔特定的時間對數(shù)據(jù)庫進(jìn)行一次掃描国拇,檢測并刪除其中的過期鍵值對;此方式對內(nèi)存不友好惯殊,如果某些鍵值對一直不被使用酱吝,那么會造成一定量的內(nèi)存浪費(fèi)
? ? ? ?3、 惰性刪除(被動刪除):鍵值對過期暫時不進(jìn)行刪除土思,至于刪除的時機(jī)與鍵值對的使用有關(guān)务热,當(dāng)獲取鍵時先查看其是否過期,過期就刪除己儒,否則就保留崎岂;此方式是定時刪除和惰性刪除的折中
Reids采用的是惰性刪除和定時刪除的結(jié)合
2、內(nèi)存淘汰機(jī)制
volatile-lru:從已設(shè)置過期時間的數(shù)據(jù)集中挑選最近最少使用的數(shù)據(jù)淘汰(linkedhashmap)闪湾。
volatile-ttl:從已設(shè)置過期時間的數(shù)據(jù)集中挑選將要過期的數(shù)據(jù)淘汰该镣。
volatile-random:從已設(shè)置過期時間的數(shù)據(jù)集中任意選擇數(shù)據(jù)淘汰。
volatile-lfu:從已設(shè)置過期時間的數(shù)據(jù)集挑選使用頻率最低的數(shù)據(jù)淘汰响谓。
allkeys-lru:從數(shù)據(jù)集中挑選最近最少使用的數(shù)據(jù)淘汰
allkeys-lfu:從數(shù)據(jù)集中挑選使用頻率最低的數(shù)據(jù)淘汰损合。
allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰
no-enviction(驅(qū)逐):禁止驅(qū)逐數(shù)據(jù),這也是默認(rèn)策略娘纷。意思是當(dāng)內(nèi)存不足以容納新入數(shù)據(jù)時嫁审,新寫入操作就會報(bào)錯,請求可以繼續(xù)進(jìn)行赖晶,線上任務(wù)也不能持續(xù)進(jìn)行律适,采用no-enviction策略可以保證數(shù)據(jù)不被丟失。
7遏插、redis事務(wù)
7.1) Redis事務(wù)的三個階段
????????事務(wù)開始 MULTI
????????命令入隊(duì)
????????事務(wù)執(zhí)行 EXEC
事務(wù)執(zhí)行過程中捂贿,如果服務(wù)端收到有EXEC、DISCARD胳嘲、WATCH厂僧、MULTI之外的請求,將會把請求放入隊(duì)列中排隊(duì)
7.2) Redis事務(wù)相關(guān)命令
????????Redis事務(wù)功能是通過MULTI了牛、EXEC颜屠、DISCARD和WATCH 四個原語實(shí)現(xiàn)的
????????Redis會將一個事務(wù)中的所有命令序列化,然后按順序執(zhí)行鹰祸。
????????redis 不支持回滾甫窟,“Redis 在事務(wù)失敗時不進(jìn)行回滾,而是繼續(xù)執(zhí)行余下的命令”蛙婴, 所以 Redis 的內(nèi)部可以保持簡單且快速粗井。
????????如果在一個事務(wù)中的命令出現(xiàn)錯誤,那么所有的命令都不會執(zhí)行;
????????如果在一個事務(wù)中出現(xiàn)運(yùn)行錯誤浇衬,那么正確的命令會被執(zhí)行懒构。
????????WATCH 命令是一個樂觀鎖,可以為 Redis 事務(wù)提供 check-and-set (CAS)行為径玖〕掌ⅲ可以監(jiān)控一個或多個鍵,一旦其中有一個鍵被修改(或刪除)梳星,之后的事務(wù)就不會執(zhí)行赞赖,監(jiān)控一直持續(xù)到EXEC命令。
????????MULTI命令用于開啟一個事務(wù)冤灾,它總是返回OK前域。MULTI執(zhí)行之后,客戶端可以繼續(xù)向服務(wù)器發(fā)送任意多條命令韵吨,這些命令不會立即被執(zhí)行匿垄,而是被放到一個隊(duì)列中,當(dāng)EXEC命令被調(diào)用時归粉,所有隊(duì)列中的命令才會被執(zhí)行椿疗。
????????EXEC:執(zhí)行所有事務(wù)塊內(nèi)的命令。返回事務(wù)塊內(nèi)所有命令的返回值糠悼,按命令執(zhí)行的先后順序排列届榄。當(dāng)操作被打斷時,返回空值 nil 倔喂。
????????通過調(diào)用DISCARD灿里,客戶端可以清空事務(wù)隊(duì)列舶沿,并放棄執(zhí)行事務(wù)鼓寺, 并且客戶端會從事務(wù)狀態(tài)中退出捶朵。
????????UNWATCH命令可以取消watch對所有key的監(jiān)控。
8悼枢、Redis實(shí)現(xiàn)分布式鎖
????????Redis為單進(jìn)程單線程模式埠忘,采用隊(duì)列模式將并發(fā)訪問變成串行訪問,我們可以使用setnx+lua萧芙,或者使用set key value px milliseconds nx 來實(shí)現(xiàn)分布式鎖给梅。
使用SETNX完成同步鎖的流程及事項(xiàng)如下:
????????使用SETNX命令獲取鎖,若返回0(key已存在双揪,鎖已存在)則獲取失敗,反之獲取成功
為了防止獲取鎖后程序出現(xiàn)異常包帚,導(dǎo)致其他線程/進(jìn)程調(diào)用SETNX命令總是返回0而進(jìn)入死鎖狀態(tài)渔期,需要為該key設(shè)置一個“合理”的過期時間。
????????釋放鎖,使用DEL命令將鎖數(shù)據(jù)刪除疯趟。
如何解決 Redis 的并發(fā)競爭 Key 問題
????????所謂 Redis 的并發(fā)競爭 Key 的問題也就是多個系統(tǒng)同時對一個 key 進(jìn)行操作拘哨,但是最后執(zhí)行的順序和我們期望的順序不同,這樣也就導(dǎo)致了結(jié)果的不同信峻!
????????推薦一種方案:分布式鎖(zookeeper 和 redis 都可以實(shí)現(xiàn)分布式鎖)倦青。(如果不存在 Redis 的并發(fā)競爭 Key 問題,不要使用分布式鎖盹舞,這樣會影響性能)
????????基于zookeeper臨時有序節(jié)點(diǎn)可以實(shí)現(xiàn)的分布式鎖产镐。大致思想為:每個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應(yīng)的指定節(jié)點(diǎn)的目錄下踢步,生成一個唯一的瞬時有序節(jié)點(diǎn)癣亚。判斷是否獲取鎖的方式很簡單,只需要判斷有序節(jié)點(diǎn)中序號最小的一個获印。當(dāng)釋放鎖的時候述雾,只需將這個瞬時節(jié)點(diǎn)刪除即可。同時兼丰,其可以避免服務(wù)宕機(jī)導(dǎo)致的鎖無法釋放玻孟,而產(chǎn)生的死鎖問題。完成業(yè)務(wù)流程后鳍征,刪除對應(yīng)的子節(jié)點(diǎn)釋放鎖黍翎。
????????在實(shí)踐中,當(dāng)然是從以可靠性為主蟆技。所以首推Zookeeper玩敏。
redisson分布式鎖實(shí)現(xiàn)原理
????????redisson有對redlock算法的封裝。其大致的工作原理如下
9质礼、Spring Boot 監(jiān)聽 Redis Key 失效事件實(shí)現(xiàn)定時任務(wù)
????????原理:通過監(jiān)聽 Redis 提供的過期隊(duì)列來實(shí)現(xiàn)旺聚,監(jiān)聽過期隊(duì)列后,如果 Redis 中某一個 KV 鍵值對過期了眶蕉,那么將向監(jiān)聽者發(fā)送消息砰粹,監(jiān)聽者可以獲取到該鍵值對的 K。因?yàn)槭谦@取不到 V 的造挽,所以key的設(shè)定必須能夠精準(zhǔn)定位碱璃。
1、開啟 Redis key 過期提醒
redis.conf
? 設(shè)置notify-keyspace-events Ex
2饭入、引入依賴
<dependency>
? ? <groupId>org.springframework.boot</groupId>
? ? <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
3嵌器、相關(guān)配置
@Configuration
public class RedisListenerConfig {
? ? @Bean
? ? RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
? ? ? ? RedisMessageListenerContainer container = new RedisMessageListenerContainer();
? ? ? ? container.setConnectionFactory(connectionFactory);
? ? ? ? return container;
? ? }
}
4、定義監(jiān)聽器 RedisKeyExpirationListener谐丢,實(shí)現(xiàn)KeyExpirationEventMessageListener?接口爽航,
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
? ? public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
? ? ? ? super(listenerContainer);
? ? }
? ? /**
? ? * 針對 redis 數(shù)據(jù)失效事件蚓让,進(jìn)行數(shù)據(jù)處理
? ? * @param message
? ? * @param pattern
? ? */
? ? @Override
? ? public void onMessage(Message message, byte[] pattern) {
? ? ? ? // 獲取到失效的 key,進(jìn)行取消訂單業(yè)務(wù)處理
? ? ? ? String expiredKey = message.toString();
? ? ? ? System.out.println("redisKey過期"+expiredKey);
? ? }
5讥珍、test查看效果
@Test
public? void redisTest() throws InterruptedException {
? ? stringRedisTemplate.opsForValue().set("bike", "100", 10, TimeUnit.MILLISECONDS);
? ? Thread.sleep(10000);
}
6历极、效果