??Redis是大規模互聯網應用常用的記憶體高速快取資料庫,它的讀寫速度非常快,據官方 Bench-mark的資料,它讀的速度能到11萬次/秒,寫的速度是8.1萬次/秒,
1. 認識Spring Cache
??在很多應用場景中通常是獲取前后相同或更新不頻繁的資料,比如訪問產品資訊資料、網頁資料,如果沒有使用快取,則訪問每次需要重復請求資料庫,這會導致大部分時間都耗費在資料庫查詢和方法呼叫上,因為資料庫進行I/O操作非常耗費時間,這時就可以利用Spring Cache來解決,
??Spring Cache是Spring提供的一整套快取解決方案,它本身并不提供快取實作,而是提供統 一的介面和代碼規范、配置、注解等,以便整合各種Cache方案,使用戶不用關心Cache的細節,
??Spring支持“透明”地向應用程式添加快取,將快取應用于方法,在方法執行前檢查快取中是否有可用的資料,這樣可以減少方法執行的次數,同時提高回應的速度,快取的應用方式“透明”, 不會對呼叫者造成任何干擾,只要通過注解@EnableCaching啟用了快取支持,Spring Boot就會自動處理好快取的基礎配置,
??Spring Cache作用在方法上,當呼叫一個快取方法時,會把該方法引數和回傳結果作為一個 “鍵值對”(key/value )存放在快取中,下次用同樣的引數來呼叫該方法時將不再執行該方法,而是直接從快取中獲取結果進行回傳,所以在使用Spring Cache 時,要保證在快取的方法和方法引數相同時回傳相同的結果,
??1.1 宣告式快取注解
??Spring Boot提供的宣告式快取(cache)注解,見表11-1,
??
圖 11-1
??1.@EnableCaching
??標注在入口類上,用于開啟快取,
??2.@Cacheable
??可以作用在類和方法上,以鍵值對的方式快取類或方法的回傳值,鍵可以有默認策略和自定義策略,
??@Cacheable注解會先查詢是否己經有快取,如果己有則會使用快取,如果沒有則會執行方法并進行快取,
??@Cacheabfe 可以指定 3 個屬性----- value、key 和 condition,
-
- value :快取的名稱,在Spring組態檔中定義,必須指定至少一個,如, @Cacheable(value= "https://www.cnblogs.com/liwenruo/archive/2022/08/11/cache1" )、@Cacheable(value=https://www.cnblogs.com/liwenruo/archive/2022/08/11/{"cache1" , "cache2n },
- key:快取的key可以為空,如果自定義key,則要按照SpEL運算式撰寫,可以自動按照方法的引陣列合,如,@Cacheable(value= "https://www.cnblogs.com/liwenruo/archive/2022/08/11/cache1",key= "#id” )
- condition:快取的條件可以為空,如果自定義condition,則使用SpEL運算式輻寫,以返 回true或false值,只有回傳true才進行快取,如,@Cacheable(value= https://www.cnblogs.com/liwenruo/archive/2022/08/11/“cache1" ,condition= "#id.length()>2" ),
??@Cacheable注解的使用方法見以下代碼:
@Override
@Cacheable(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/emp",key = "targetClass + methodName + #p0")
public List<Card> getCardList() {
return cardRepository.findAll();
}
代碼解釋如下,
- value是必需的,它指定了快取存放的位置,
- key使用的是SpEL運算式,
- User物體類一定要實作序列化,否則會報“java.io.NotSerializableException”例外,序 列化可以繼承 Serializable,如 public class User implements Serializable,
??3. @CachePut
??@CachePut標注的方法在執行前不檢查快取中是否存在之前執行過的結果,而是每次都會執行該方法,并將執行結果以鍵值對的形式存入指定的快取中,和@Cacheable不同的是, @CachePut每次都會觸發真實方法的呼叫,比如用戶更新快取資料,
??需要注意的是,該注解的value和key必須與要更新的快取相同,即與@Cacheable 相同, 具體見下面兩段代碼:
@Override
@CachePut(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/usr",key = "targetClass + #p0")
public Book update(Book book) {
return null;
}
@Override
@Cacheable(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/usr",key = "targetClass + #p0")
public Book save(Book book) {
return null;
}
??4. @CacheEvict
??@CacheEvict用來標注需要清除快取元素的方法或類,該注解用于觸發快取的清除操作,其屬性有value、key、condition、allEntries 和 beforeInvocation,可以用這些屬性來指定清除的條件,使用方法如下:
@Override
@Cacheable(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/usr",key = "#p0.id")
public Book save(Book book) {
return null;
}
@Override
@CacheEvict(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/usr",key = "#id")
public void delete(int id) {
}
@Override
@CacheEvict(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/accountCache",allEntries = true)
public void deleteAll() {
}
@Override
@CacheEvict(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/accountCache",beforeInvocation = true)
public void deleteAll() {
}
??5. @Caching
??注解@Caching用來組合多個注解標簽,有3個屬性:cacheable、put 和 evict,用于指定 @Cacheable、@CachePut 和 @CacheEvict,使用方法如下:
@Override
@Caching(cacheable = {@Cacheable(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/usr",key = "#p0"),},
put = {@CachePut(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/usr",key = "#p0"),},
evict = {@CacheEvict(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/usr",key = "#p0"),})
public Book save(Book book) {
return null;
}
??1.2 實體:用Spring Cache進行快取管理
??本實體展示Spring Cache是如何使用簡單快取(SIMPLE方式)進行快取管理的,
??(1)添加依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>2.7.2</version>
</dependency>
??(2)配置快取管理器
??在application.yml檔案中配置目標快取管理器,支持Ehcache、Generic、Redis、 Jcache 等,這里使用 SIMPLE 方式 "spring: cache: type: SIMPLE”,
??(3)開啟快取功能
??在入口類添加注解@EnableCaching,開啟快取功能,
??(4)在服務實作里撰寫快取業務邏輯:
@Service
public class BookServiceImpl implements BookService{
@Autowired
private BookDao bookDao;
@Override
public Book getById(Integer id) {
return bookDao.getById(id);
}
@Override
public void insert(Book book) {
bookDao.insert(book);
}
@Override
@CachePut(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/usr",key = "targetClass + #p0")
public Book update(Book book) {
return null;
}
@Override
@Caching(cacheable = {@Cacheable(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/usr",key = "#p0"),},
put = {@CachePut(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/usr",key = "#p0"),},
evict = {@CacheEvict(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/usr",key = "#p0"),})
public Book save(Book book) {
return null;
}
@Override
@CacheEvict(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/usr",key = "#id")
public void delete(int id) {
}
@Override
@CacheEvict(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/accountCache",allEntries = true)
public void deleteAll() {
}
}
??上述代碼可以看出,查找用戶的方法使用了注解@Cacheable來開啟快取,修改和添加方法使用了注解@CachePut,它是先處理方法,然后把結果進行快取的,要想洗掉資料,則需要使用注解@CacheEvict來清空快取,
??(5)控制器里呼叫快取服務
查看代碼
@EnableCaching
@Controller
public class BookController {
@Autowired
private BookService bookService;
int id = 0;
@RequestMapping("/book")
public String insert(){
Book book = new Book();
book.setUsername("拉行啊");
book.setPassword("123");
String jsonObject = JSON.toJSONString(book);
System.out.println(jsonObject);
book.setJson(jsonObject);
bookService.insert(book);
id = book.getId();
return book.toString();
}
@RequestMapping(value = "https://www.cnblogs.com/get",method = RequestMethod.GET,produces = "application/json")
public Book get(){
Book book = new Book();
book.setUsername("拉行啊");
book.setPassword("123");
return book;
}
@RequestMapping(value = "https://www.cnblogs.com/put")
public String put(@RequestParam("upload")MultipartFile file, RedirectAttributes redirectAttributes){
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
String nyr = dateFormat.format(date);
if (file.getOriginalFilename().endsWith(".jpg")||file.getOriginalFilename().endsWith(".png")||
file.getOriginalFilename().endsWith(".git")){
try {
byte[] bytes = file.getBytes();
String s = nyr+Math.random()+file.getOriginalFilename();
Path path = Paths.get("./"+s);
Files.write(path, bytes);
return "success";
} catch (Throwable e) {
e.printStackTrace();
}
}else {
return "格式不支持";
}
return "error";
}
@RequestMapping(value = "https://www.cnblogs.com/test")
public String test(Model model) throws Exception{
Book book = new Book();
book.setPassword("123");
model.addAttribute("book",book);
return "test";
}
}
??1.3 整合 Ehcache
??Spring Boot支持多種不同的快取產品,在默認情況下使用的是簡單快取,不建議在正式環境中使用,我們可以配置一些更加強大的快取,比如Ehcache,Ehcache是一種廣泛使用的開源Java分布式快取,它具有記憶體和磁盤存盤、快取加載器、快取擴展、快取例外處理、GZIP快取、Servlet過濾器,以及支持REST和SOAP API等特點,
@Service
@CacheConfig(cacheNames = {"userCache"})
public class BookServiceImpl implements BookService{
@Autowired
private BookDao bookDao;
@Override
@Cacheable(value = "https://www.cnblogs.com/liwenruo/archive/2022/08/11/usr",key = "targetClass + #p0")
public Page<Book> findAll() {
return bookDao.findAll();
}
}
??1.4 整合 Caffeine
??Caffeine是使用Java 8對Guava快取的重寫版本,它基于LRU演算法實作,支持多種快取過期策略,要使用它,需要在pom.xml檔案中增加Caffeine依賴,這樣Spring Boot就會自動用 Caffeine替換默認的簡單快取,
??增加Caffeine依賴的代碼如下:
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
??然后配置引數,見以下代碼:
spring:
cache:
type: caffeine
cache-names: myCaffeine
caffeine:
spec: maximumSize=1,expireAfterAccess=5s
代碼解釋如下,
- cache.type:指定使用哪個快取供應商,
- cache.cache-names:在啟動時創建快取名稱(即前面的cacheNames ),如果有多個名稱,則用逗號進行分隔,
- cache.caffeine.spec:這是 Caffeine 快取的專用配置,
- maximumSize=1:最大快取數量,如果超出最大快取數量,則保留后進(最新)的,最開始的快取會被清除,
- expireAfterAccess=5s:快取5s,即快取在5 s之內沒有被使用,就會被清除,在默認情況下,快取的資料會一直保存在記憶體中,有些資料可能用一次后很長時間都不會再月,這樣會有大量無用的資料長時間占用記憶體,我們可以通過配置及時清除不需要的快取,
2. 認識Redis
??2.1 對比 Redis 與 Memcached
??Cache可以和Redis一起用,Spring Boot支持把Cache存到Redis里,如果是單服務器, 則用Cache、Ehcache或Caffeine,性能更高也能滿足需求,如果擁有服務器集群,則可以使用 Redis,這樣性能更高,
??1. Redis
??Redis是目前使用最廣泛的記憶體資料存盤系統之一,它支持更豐富的資料結構,支持資料持久化、事務、HA (高可用High Available)雙機集群系統、主從庫,
??Redis是key-value存盤系統,它支持的value型別包括String、List、Set、Zset (有序集合)和Hash,這些資料型別都支持push/pop、add/remove,以及取交集、并集、差集或更豐富的操作,而且這些操作都是原子性的,在此基礎上,Redis支持各種不同方式的排序和演算法,
??Redis會周期性地把更新后的資料寫入磁盤,或把修改操作寫入追加的記錄檔案中(RDB和 AOF兩種方式),并且在此基礎上實作了 master-slave (主從)同步,機器重啟后,能通過持久化資料自動重建記憶體,如果使用Redis作為Cache,則機器宕機后熱點資料不會丟失,
??豐富的資料結構加上Redis兼具快取系統和資料庫等特性,使得Redis擁有更加豐富的應用場景,
??Redis可能會導致的問題:
-
- 快取和資料庫雙寫一致性問題,
- 快取雪崩問題,
- 快取擊穿問題,
- 快取的并發競爭問題,
??Redis為什么快:
-
- 純記憶體操作,
- 單執行緒操作,避免了頻繁的背景關系切換,
- 采用了非阻塞I/O多路復用機制,
??2. Memcached
??Memcached的協議簡單,它基于Libevent的事件處理,內置記憶體存盤方式,Memcached 的分布式不互相通信,即各個Memcached不會互相通信以共享資訊,分布策略由客戶端實作,它不會對資料進行持久化,重啟Memcached、重啟作業系統都會導致全部資料消失,
??Memcached常見的應用場景一存盤一些讀取頻繁但更新較少的資料,如靜態網頁、系統配置及規則資料、活躍用戶的基本資料和個性化定制資料、實時統計資訊等,
??3. 比較 Redis 與 Memcached
??(1)關注度,
????近年來,Redis越來越火熱,人們對Redis的關注度越來越高;對 Memcached關注度比較平穩,且有下降的趨勢,
??(2)性能,
????兩者的性能都比較高,
??(3)資料型別,
????Memcached的資料結構單一,
????Redis非常豐富,
??(4)記憶體大小,
????Redis在2.0版本后增加了自己的VM特性,突破物理記憶體的限制,
????Memcached可以修改最大可用記憶體的大小來管理記憶體,采用LRU演算法.
??(5)可用性,
????Redis依賴客戶端來實作分布式讀寫,在主從復制時,每次從節點重新連接主節點都要依賴整個快照,無增量復制,Redis不支持自動分片(sharding),如果要實作分片功能,則需要依賴程式設定一致的散列(hash)機制,
????Memcached采用成熟的hash或環狀的演算法,來解決單點故障引起的抖動問題,其本身沒有資料冗余機制,
??(6)持久化,
????Redis依賴快照、AOF進行持久化,但AOF在增強可靠性的同時,對性能也有所影響,
????Memcached不支持持久化,通常用來做快取,以提升性能,
??(7)value資料大小,
????Redis的value的最大限制是1GB,
????Memcached只能保存1MB以內的資料,
??(8)資料一致性(事務支持),
????Memcached在并發場景下用CAS保證一致性,
????Redis對事務支持比較弱,只能保證事務中的每個操作連續執行,
??(9)應用場景,
????Redis:適合資料量較少、性能操作和運算要求高的場景,
????Memcached:適合提升性能的場景,適合讀多與少,如果資料量比較大,則可以采用分片的方式來解決,
??2.2 Redis的適用場景
- 高并發的讀寫
????Redis特別適合將方法的運行結果放入快取,以便后續在請求方法時直接去快取中讀取,對執行耗時,且結果不頻繁變動的SQL查詢的支持極好,
????在高并發的情況下,應盡暈避免請求直接訪問資料庫,這時可以使用Redis進行緩沖操作,讓請求先訪問Redis,
- 計數器
????電商網站(APP)商品的瀏覽量、視頻網站(APP)視頻的播放數等資料都會被統計,以便用于運營或產品分析,為了保證資料實時生效,每次瀏覽都得+1,這會導致非常高的并發量,這時可以用Redis提供的incr命令來實作計數器功能,這一切在記憶體中操作,所以性能非常好,非常適用于這些計數場景,
- 排行榜
????可以利用Redis提供的有序集合資料類,實作各種復雜的排行榜應用,如京東、淘寶的銷量榜單,商品按時間、銷量排行等,
- 分布式會話
????在集群模式下,一般都會搭建以Redis等記憶體資料庫為中心的Session (會活)服務,它不再由容器管理,而是由Session服務及記憶體資料庫管理,
- 互動場景
????使用Redis提供的散列、集合等資料結構,可以很方便地實作網站(APP)中的點贊、踩、關注共同好友等社交場景的基本功能,
- 最新串列
????Redis可以通過LPUSH在串列頭部插入一個內容ID作為關鍵字,LTRIM可用來限制串列的數量,這樣串列永遠為N個ID,無須查詢最新的串列,直接根據ID查找対應的內容即可,
3. Redis的資料型別
??Redis有5種資料型別,見表11-2,
??
表 11-2
- 字串(string)
????Redis字串可以包含任意型別的資料、字符、整數、浮點數等,
????一個字串型別的值的容量有512MB,代表能存盤最大512MB的內容,
????可以使用INCR (DECR、INCRBY)命令來把字串當作原子計敬器使用,
????使用APPEND命令在字串后添加內容,
????應用場景:計數器,
- 串列(list)
????Redis串列是簡單的字串串列,按照插入順序排序,可以通過LPUSH、RPUSH命令添加一個元素到串列的頭部或尾部,
????一個串列最多可以包含以”232-1“(4294967295)個元素,
????應用場景:取最新N個資料的操作、訊息佇列、洗掉與過濾、實時分析正在發生的情況,資料統計與防止垃圾郵件(結合Set ),
- 集合(set)
????Redis集合是一個無序的、不允許相同成員存在的字串合集,
????支持一些服務器端的命令從現有的集合出發去進行集合運算,如合并(并集:union)、求交(交集intersection)、差集,找出不同元素的操作(共同好友、二度好友),
????應用場景:Unique操作,可以獲取某段時間內所有資料“排重值”,比如用于共同好友、二度好友、統計獨立IP、好友推薦等,
- 散列(hash )
????Redis hash是字串欄位和字串值之間的映射,主要用來表示物件,也能夠存盤許多元素,
????應用場景:存盤、讀取、修改用戶屬性,
- 有序集合(sorted set、zset)
????Redis有序集合和Redis集合類似,是不包含相同字串的合集,每個有序集合的成員都關聯著一個評分,這個評分用于把有序集合中的成員按最低分到最高分排列(排行榜應用,取TOP N 操作),
????使用有序集合,可以非常快捷地完成添加、洗掉和更新元素的操作,元素是在插入時就排好序 的,所以很快地通過評分(score )或位次(position )獲得一個范圍的元素,
????應用場景:排行榜應用、取TOP N、需要精準設定過期時間的應用(時間戳作為Score)、帶有權重的元素(游戲用戶得分排行榜)、過期專案處理、按照時間排序等,
4. 用RedisTemplate操作Redis的五種資料型別
??4.1 認識opsFor方法
Spring封裝了 RedisTemplate來操作Redis,它支持所有的Redis原生的API,在 RedisTemplate中定義了對5種資料結構的操作方法,
-
- opsForValueQ:操作字串,
- opsForHashO:操作散列,
- opsForList():操作串列,
- opsForSet():操作集合,
- opsForZSetO:操作有序集合,
下面通過實體來理解和應用這些方法,這里需要特別注意的是,運行上述方法后要對資料進行清空操作,否則多次運行會導致資料重復操作,
4.2 操作字串
??字串(string )是Redis最基本的型別,string的一個“key”對應一個"value”,即key-value 鍵值對,string是二進制安全的,可以存盤任何資料(比如圖片或序列化的物件),值最大能存盤512MB的資料,一般用于一些復雜的計數功能的快取,RedisTemplate提供以下操作string的方法,
??(1)set void set(K key, V value);get V get(Object key)
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
redisTemplate.opsForValue().set("hello", "world");
redisTemplate.opsForValue().set("staing","somewhere");
Object s = redisTemplate.opsForValue().get("hello");
Object s2 = redisTemplate.opsForValue().get("staing");
System.out.println(s);
System.out.println(s2);
}
}
??(2)set void set(K key, V value, long timeout, TimeUnit unit)
??以下代碼設定3 s失效,3 s之內查詢有結果,3 s之后查詢則回傳為null,具體用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void String(){
redisTemplate.opsForValue().set("hello", "world",3, TimeUnit.SECONDS);
try {
Object s = redisTemplate.opsForValue().get("hello");
System.out.println(s);
Thread.currentThread().sleep(2000);
s = redisTemplate.opsForValue().get("hello");
System.out.println(s);
Thread.currentThread().sleep(2000);
s = redisTemplate.opsForValue().get("hello");
System.out.println(s);
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
TimeUnit是java.util.concurrent包下面的一個類,表示給定單元粒度的時間段,常用的顆粒度有:
- 小時(TimeUnit.HOURS )
- 分鐘(TimeUnit.MINUTES )
- 秒(TimeUnit.SECONDS )
- 毫秒(TimeUnit.MILLISECONDS )
??(3)set void set(K key, V value, long offset)
??給定key所存盤的字串值,從偏移量 offset開始,具體用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
redisTemplate.opsForValue().set("key", "hello world",6);
System.out.println(redisTemplate.opsForValue().get("key"));
}
}
??運行測驗,輸出如下結果:
??hello
??(4)getAndSet V getAndSet(K key, V value)
??設定鍵的字串值,并回傳其舊值,具體用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
redisTemplate.opsForValue().set("hello", "world");
System.out.println(redisTemplate.opsForValue().getAndSet("hello", "hey"));
System.out.println(redisTemplate.opsForValue().get("hello"));
}
}
??運行測驗,輸出如下結果:
??world
??hey
??(5)append Integer append(K key, String value)
??如果key已經存在,并且是一個字串,則該命令將該值追加到字串的末尾,如果key不存在,則它將被創建并設定為空字串,因此append在這種特殊情況下類似于set,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate<String,String> redisTemplate;
@Test
void test() {
redisTemplate.opsForValue().append("hello", "hello");
System.out.println(redisTemplate.opsForValue().get("hello"));
redisTemplate.opsForValue().append("hello", "world");
System.out.println(redisTemplate.opsForValue().get("hello"));
}
}
??運行測驗,輸出如下結果:
??hello
??helloworld
??這里一定要注意反序列化配置,否則會報借,
??(6)size Long size(K key)
??回傳key所對應的value值的長度,見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
redisTemplate.opsForValue().set("key", "1");
System.out.println(redisTemplate.opsForValue().size("key"));
}
}
??運行測驗,輸岀如下結果:
??3
??4.3 操作散列
??Redis hash (散列)是一個string型別的field和value的映射表,hash特別適合用于存盤物件,value中存放的是結構化的物件.利用這種資料結構,可以方便地操作其中的某個欄位,比如在“單點登錄”時,可以用這種資料結構存盤用戶資訊,以Cookield作為key,設定30分鐘為快取過期時間,能很好地模擬出類似Session的效果,
??(1)void putAII(H key, Map<? extends HK, ? extends HV> m)
????用m中提供的多個散列欄位設定到key對應的散串列中,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("key1", "value1");
map.put("key2", "value2");
redisTemplate.opsForHash().putAll("HASH",map);
System.out.println(redisTemplate.opsForHash().entries("HASH"));
}
}
??運行測驗,輸出如下結果:
??{key1=value1, key2=value2}
??(2)void put(H key, HK hashKey, HV value)
????設定hashKey的值,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
redisTemplate.opsForHash().put("redis","name","li");
redisTemplate.opsForHash().put("redis","sex","male");
System.out.println(redisTemplate.opsForHash().entries("redis"));
}
}
??運行測驗,輸出如下結果:
??{name=li, sex=male}
??(3)List<HV> values(H key)
??根據密鑰獲取整個散列存盤的值,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
redisTemplate.opsForHash().put("redis","name","li");
redisTemplate.opsForHash().put("redis","sex","male");
System.out.println(redisTemplate.opsForHash().values("redis"));
}
}
??運行測驗,輸出如下結果:
??[li, male]
??(4)Map<HK, HV> entries(H key)
??根據密鑰獲取整個散列存盤,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
redisTemplate.opsForHash().put("redis","name","li");
redisTemplate.opsForHash().put("redis","sex","male");
System.out.println(redisTemplate.opsForHash().entries("redis"));
}
}
??運行測驗,輸出如下結果:
??{name=li, sex=male}
??(5)Long delete(H key, Object... hashKeys)
??洗掉給定的hashKeys,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
redisTemplate.opsForHash().put("redis","name","li");
redisTemplate.opsForHash().put("redis","sex","male");
System.out.println(redisTemplate.opsForHash().delete("redis","name"));
System.out.println(redisTemplate.opsForHash().entries("redis"));
}
}
??運行測驗,輸出如下結果:
??1
??{sex=male}
??(6)Boolean hasKey(H key, Object hashKey)
??確定hashKey是否存在,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
redisTemplate.opsForHash().put("redis","name","li");
redisTemplate.opsForHash().put("redis","sex","male");
System.out.println(redisTemplate.opsForHash().hasKey("redis","name"));
System.out.println(redisTemplate.opsForHash().hasKey("redis","sex"));
}
}
??運行測驗,輸出如下結果:
??true
??true
??(7)HV get(H key, Object hashKey)
??從鍵中的散列獲取給定hashKey的值,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
redisTemplate.opsForHash().put("redis","name","li");
redisTemplate.opsForHash().put("redis","sex","male");
System.out.println(redisTemplate.opsForHash().get("redis","name"));
}
}
??運行測驗,輸出如下結果:
??li
??(8)Set<HK> keys(H key)
??獲取key所對應的key的值,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
redisTemplate.opsForHash().put("redis","name","li");
redisTemplate.opsForHash().put("redis","sex","male");
System.out.println(redisTemplate.opsForHash().keys("redis"));
}
}
??運行測驗,輸出如下結果:
??[sex, name]
??(9)Long size(H key)
??獲取key所對應的散串列的大小個數,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
redisTemplate.opsForHash().put("redis","name","li");
redisTemplate.opsForHash().put("redis","sex","male");
System.out.println(redisTemplate.opsForHash().size("redis"));
}
}
??運行測驗,輸出如下結果:
??2
??4.4 操作串列
??Redis串列是簡單的字串串列,按照插入順序排序,可以添加一個元素到串列的頭部(左邊) 或尾部(右邊),
?? 使用list資料結構,可以做簡單的訊息佇列的功能,還可以利用Irange命令,做基于Redis的分頁功能,性能極佳,而使用SQL陳述句做分頁功能往往效果扱差,
??(1)Long leftPushAII(K key, V... values)
????leftPushAII表示把一個陣列插入串列中,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[] {"1","2","3"};
redisTemplate.opsForList().leftPushAll("list",strings);
System.out.println(redisTemplate.opsForList().range("list",0,-1));
}
}
??運行測驗,輸岀如下結果:
??[3,2,1]
??(2)Long size(K key)
????回傳存盤在鍵中的串列的長度,如果鍵不存在,則將其解釋為空串列,并回傳0,如果key存盤的值不是串列,則回傳錯誤,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[] {"1","2","3"};
redisTemplate.opsForList().leftPushAll("list",strings);
System.out.println(redisTemplate.opsForList().size("list"));
}
}
??運行測驗,輸岀如下結果:
??6
??(3)Long leftPush(K key, V value)
????將所有指定的值插入在鍵的串列的頭部,如果鍵不存在,則在執行推送操作之前將其創建為空串列(從左邊插入),用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
redisTemplate.opsForList().leftPush("list","1");
System.out.println(redisTemplate.opsForList().size("list"));
redisTemplate.opsForList().leftPush("list","2");
System.out.println(redisTemplate.opsForList().size("list"));
redisTemplate.opsForList().leftPush("list","3");
System.out.println(redisTemplate.opsForList().size("list"));
}
}
??(4)Long rightPush(K key, V value)
????將所有指定的值插入存盤在鍵的串列的頭部,如果鍵不存在,則在執行推送操作之前將其創建為空串列(從右邊插入),用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
redisTemplate.opsForList().rightPush("list","1");
System.out.println(redisTemplate.opsForList().size("list"));
redisTemplate.opsForList().rightPush("list","2");
System.out.println(redisTemplate.opsForList().size("list"));
redisTemplate.opsForList().rightPush("list","3");
System.out.println(redisTemplate.opsForList().size("list"));
}
}
??(5)Long rightPushAII(K key, V... values)
????通過rightPushAII方法向最右邊批量添加元素,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[]{"1", "2", "3"};
redisTemplate.opsForList().rightPushAll("list",strings);
System.out.println(redisTemplate.opsForList().range("list",0,-1));
}
}
??(6)void set(K key, long index, V value)
????在串列中index的位置設定value,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[]{"1", "2", "3"};
redisTemplate.opsForList().rightPushAll("list",strings);
System.out.println(redisTemplate.opsForList().range("list",0,-1));
redisTemplate.opsForList().set("list",1,"值");
System.out.println(redisTemplate.opsForList().range("list",0,-1));
}
}
??運行測驗,輸出如下結果:
??[1, 2, 3]
??[1, 值, 3]
??(7)Long remove(K key, long count, Object value)
???從存盤在鍵中的串列,洗掉給定“count”值的元素的第1個計數事件,其中,引數count的 含義如下,
-
- count=0:洗掉等于value的所有元素,
- count>0:洗掉等于從頭到尾移動的值的元素:
- counK<0:洗掉等于從尾到頭移動的值的元素,
以下代碼用于洗掉串列中第一次出現的值,
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[]{"1", "2", "3"};
redisTemplate.opsForList().rightPushAll("list",strings);
System.out.println(redisTemplate.opsForList().range("list",0,-1));
redisTemplate.opsForList().remove("list",1,"2");
System.out.println(redisTemplate.opsForList().range("list",0,-1));
}
}
??運行測驗,輸出如下結果:
??[1, 2, 3]
??[1, 3]
??(8)V index(K key, long index)
????根據下標獲取串列中的值(下標從0幵始),用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[]{"1", "2", "3"};
redisTemplate.opsForList().rightPushAll("list",strings);
System.out.println(redisTemplate.opsForList().range("list",0,-1));
System.out.println(redisTemplate.opsForList().index("list",2));
}
}
??運行測驗,輸出如下結果:
??[1, 2, 3]
??3
??(9)V leftPop(K key)
????彈出最左邊的元素,彈出之后該值在串列中將不復存在,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[]{"1", "2", "3"};
redisTemplate.opsForList().rightPushAll("list",strings);
System.out.println(redisTemplate.opsForList().range("list",0,-1));
System.out.println(redisTemplate.opsForList().leftPop("list"));
System.out.println(redisTemplate.opsForList().range("list",0,-1));
}
}
??運行測驗,輸出如下結果:
??[1, 2, 3]
??1
??[2, 3]
??(10)V rightPop(K key)
????彈出最右邊的元素,彈出之后該值任串列中將不復存在,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[]{"1", "2", "3"};
redisTemplate.opsForList().rightPushAll("list",strings);
System.out.println(redisTemplate.opsForList().range("list",0,-1));
System.out.println(redisTemplate.opsForList().rightPop("list"));
System.out.println(redisTemplate.opsForList().range("list",0,-1));
}
}
??運行測驗,輸出如下結果:
??[1, 2, 3]
??3
??[1, 2]
??4.5 操作集合
??set是存放不重復值的集合,利用set可以做全域去重的功能,還可以進行交集、并集、差集等 操作,也可用來實作計算共同喜好、全部的喜好、自己獨有的喜好等功能,
??Redis的set是string型別的無序集合,通過散串列實作,
??(1)Long add(K key, .. values)
????在無序集合中添加元素,回傳添加個數,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[]{"str1", "str2"};
System.out.println(redisTemplate.opsForSet().add("set1",strings));
System.out.println(redisTemplate.opsForSet().add("set1","1","2","3"));
}
}
??運行測驗,輸出如下結果:
??2
??3
??(2)Long remove(K key, Object... values)
????移除集合中一個或多個成員,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[]{"str1", "str2"};
System.out.println(redisTemplate.opsForSet().add("set1",strings));
System.out.println(redisTemplate.opsForSet().remove("set1",strings));
}
}
??運行測驗,輸出如下結果:
??2
??0
??(3)V pop(K key)
????移除并回傳集合中的一個隨機元素,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[]{"str1", "str2"};
System.out.println(redisTemplate.opsForSet().add("set1",strings));
System.out.println(redisTemplate.opsForSet().pop("set1"));
System.out.println(redisTemplate.opsForSet().members("set1"));
}
}
??運行測驗,輸出如下結果:
??2
??str2
??[str1]
??(4)Boolean move(K key, V value, K destKey)
????將member元素移動,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[]{"str1", "str2"};
System.out.println(redisTemplate.opsForSet().add("set1",strings));
redisTemplate.opsForSet().move("set1","str1","set1tostr1");
System.out.println(redisTemplate.opsForSet().members("set1"));
System.out.println(redisTemplate.opsForSet().members("set1tostr1"));
}
}
??運行測驗,輸出如下結果:
??2
??[str2]
??[str1]
??(5)Long size(K key)
????獲取無序集合的大小長度,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[]{"str1", "str2"};
System.out.println(redisTemplate.opsForSet().add("set",strings));
System.out.println(redisTemplate.opsForSet().size("set"));
}
}
??運行測驗,輸出如下結果:
??2
??2
??(6)Set<V> members(K key)
????回傳集合中的所有成員,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[]{"str1", "str2"};
System.out.println(redisTemplate.opsForSet().add("set",strings));
System.out.println(redisTemplate.opsForSet().members("set"));
}
}
??運行測驗,輸出如下結果:
??2
??[str1,str2]
??(7)Cursor<V> scan(K key, ScanOptions options)
????遍歷Set,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
String[] strings = new String[]{"str1", "str2"};
System.out.println(redisTemplate.opsForSet().add("set",strings));
Cursor<Object> cursor = redisTemplate.opsForSet().scan("set", ScanOptions.NONE);
while (cursor.hasNext()) {
System.out.println(cursor.next());
}
}
}
??運行測驗,輸岀如下結果:
??2
??str2
??str1
??4.6 操作有序集合
??zset (sorted set,有序集合)也是string型別元素的集合,且不允許重復的成員,每個元素都會關聯一個double型別的分數,可以通過分數將該集合中的成員從小到大進行排序,
??zset的成員是唯一的,但權重引數分數(score)卻可以重復,集合中的元素能夠按score進行排列,它可以用來做排行榜應用、取TOP N 延時任務、范圍查找等,
??(1)Long add(K key, Set<TypedTuple<V>>tuples)
????新增一個有序集合,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1",9.6);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2",9.9);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
System.out.println(redisTemplate.opsForZSet().add("zset",tuples));
System.out.println(redisTemplate.opsForZSet().range("zset",0,-1));
}
}
??運行測驗,輸出如下結果:
??1
??[zset-1, zset-2]
??(2)Boolean add(K key, V value, double score)
????新增一個有序集合,如果存在則回傳false,如果不存在則回傳true,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
System.out.println(redisTemplate.opsForZSet().add("zset","zset-1",1.0));
System.out.println(redisTemplate.opsForZSet().add("zset","zset-1",1.0));
}
}
??運行測驗,輸出如下結果:
??true
??false
??(3)Long remove(K key, Object... values)
????從有序集合中移除一個或多個元素,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
System.out.println(redisTemplate.opsForZSet().add("zset","zset-1",1.0));
System.out.println(redisTemplate.opsForZSet().add("zset","zset-2",1.0));
System.out.println(redisTemplate.opsForZSet().range("zset",0,-1));
System.out.println(redisTemplate.opsForZSet().remove("zset","zset-2"));
System.out.println(redisTemplate.opsForZSet().range("zset",0,-1));
}
}
??運行測驗,輸出如下結果:
??true
??true
??[zset-1, zset-2]
??1
??[zset-1]
??(4)Long rank(K key, Object o)
????回傳有序集中指定成員的排名,按分數值遞增排列,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
System.out.println(redisTemplate.opsForZSet().add("zset","zset-1",1.0));
System.out.println(redisTemplate.opsForZSet().add("zset","zset-2",1.0));
System.out.println(redisTemplate.opsForZSet().range("zset",0,-1));
System.out.println(redisTemplate.opsForZSet().remove("rank","zset-1"));
}
}
??運行測驗,輸出如下結果:
??true
??true
??[zset-1, zset-2]
??0
??(5)Set<V> range(K key, long start, long end)
????通過索引區間回傳有序集合指定區間內的成員,按分數值遞增排列,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1",9.6);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2",8.1);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
System.out.println(redisTemplate.opsForZSet().add("zset",tuples));
System.out.println(redisTemplate.opsForZSet().range("zset",0,-1));
}
}
??運行測驗,輸出如下結果:
??0
??[zset-2, zset-1]
??(6)Long count(K key, double min, double max)
????通過分數回傳有序集合指定區間內的成員個數,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1",3.6);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2",4.1);
ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3",5.7);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
tuples.add(objectTypedTuple3);
System.out.println(redisTemplate.opsForZSet().add("zset",tuples));
System.out.println(redisTemplate.opsForZSet().rangeByScore("zset",0,9));
System.out.println(redisTemplate.opsForZSet().count("zset",0,5));
}
}
??運行測驗,輸出如下結果:
??1
??[zset-1, zset-2, zset-3]
??2
??(7)Long size(K key)
????獲取有序集合的成員數,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1",3.6);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2",4.1);
ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3",5.7);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
tuples.add(objectTypedTuple3);
System.out.println(redisTemplate.opsForZSet().add("zset",tuples));
System.out.println(redisTemplate.opsForZSet().size("zset"));
}
}
??運行測驗,輸出如下結果:
??0
??3??
??(8)Double score(K key, Object o)
????獲取指定成員的score值,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1",3.6);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2",4.1);
ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3",5.7);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
tuples.add(objectTypedTuple3);
System.out.println(redisTemplate.opsForZSet().add("zset",tuples));
System.out.println(redisTemplate.opsForZSet().score("zset","zset-1"));
}
}
??運行測驗,輸出如下結果:
??0
??3.6
??(9)Long removeRange(K key, long start, long end)
????移除指定索引位置的成員,有序集成員按分數值遞增排列,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1",3.6);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2",4.1);
ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3",2.7);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
tuples.add(objectTypedTuple3);
System.out.println(redisTemplate.opsForZSet().add("zset",tuples));
System.out.println(redisTemplate.opsForZSet().range("zset",0,-1));
System.out.println(redisTemplate.opsForZSet().removeRange("zset",1,2));
System.out.println(redisTemplate.opsForZSet().range("zset",0,-1));
}
}
??運行測驗,輸岀如下結果:
??2
??[zset-3, zset-1, zset-2]
??2
??[zset-3]
??(10)Cursor<TypedTuple<V>>scan(K key, ScanOptions options)
????遍歷zset,用法見以下代碼:
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void test() {
ZSetOperations.TypedTuple<Object> objectTypedTuple1 = new DefaultTypedTuple<>("zset-1",3.6);
ZSetOperations.TypedTuple<Object> objectTypedTuple2 = new DefaultTypedTuple<>("zset-2",5.1);
ZSetOperations.TypedTuple<Object> objectTypedTuple3 = new DefaultTypedTuple<>("zset-3",2.7);
Set<ZSetOperations.TypedTuple<Object>> tuples = new HashSet<>();
tuples.add(objectTypedTuple1);
tuples.add(objectTypedTuple2);
tuples.add(objectTypedTuple3);
System.out.println(redisTemplate.opsForZSet().add("zset",tuples));
Cursor<ZSetOperations.TypedTuple<Object>> cursor = redisTemplate.opsForZSet().scan("zset",ScanOptions.NONE);
while (cursor.hasNext()) {
ZSetOperations.TypedTuple<Object> item = cursor.next();
System.out.println(item.getValue()+":"+item.getScore());
}
}
}
??運行測驗,輸出如下結果:
??2
??zset-3:2.7
??zset-1:3.6
??zset-2:5.1
??除使用opsForXXX方法外,還可以使用Execute方法,opsForXXX方法的底層,是通過呼叫Execute方法來實作的,psForXXX方法實際上是封裝了 Execute方法,定義了序列化,以便使用起來更簡單便捷,
??4.7 比較 RedisTemplate 和 StringRedisTemplate
??StringRedisTemplate繼承于RedisTemplate,兩者的資料是不相通的,
- StringRedisTemplate 只能管理 StringRedisTemplate 中的資料,
- RedisTemplate 只能管理 RedisTemplate 中的資料,
??StnngRedisTemplate默認采用的是string的序列化策略,RedisTemplate默認采用的是 JDK的序列化策略,
??
??
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/501596.html
標籤:其他
