redis-SpringBoot(21)

来源:https://www.cnblogs.com/liwenruo/archive/2022/08/11/16575571.html
-Advertisement-
Play Games

Redis是大規模互聯網應用常用的記憶體高速緩存資料庫,它的讀寫速度非常快,據官方 Bench-mark的數據,它讀的速度能到11萬次/秒,寫的速度是8.1萬次/秒。 1. 認識Spring Cache 在很多應用場景中通常是獲取前後相同或更新不頻繁的數據,比如訪問產品信息數據、網頁數據。如果沒有使用 ...


  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

  [email protected]

  標註在入口類上,用於開啟緩存。

  [email protected]

  可以作用在類和方法上,以鍵值對的方式緩存類或方法的返回值。鍵可以有預設策略和自定義策略。

  @Cacheable註解會先查詢是否己經有緩存,如果己有則會使用緩存,如果沒有則會執行方法併進行緩存。

  @Cacheabfe 可以指定 3 個屬性----- value、key 和 condition。

    • value :緩存的名稱,在Spring配置文件中定義,必須指定至少一個。如, @Cacheable(value= "cache1" )、@Cacheable(value={ "cache1" , "cache2n }。
    • key:緩存的key可以為空,如果自定義key,則要按照SpEL表達式編寫。可以自動按照方法的參數組合。如,@Cacheable(value= "cache1",key= "#id” )
    • condition:緩存的條件可以為空,如果自定義condition,則使用SpEL表達式輻寫,以返 回true或false值,只有返回true才進行緩存。如,@Cacheable(value= “cache1" ,condition= "#id.length()>2" )。

  @Cacheable註解的使用方法見以下代碼:

@Override
@Cacheable(value = "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 = "usr",key = "targetClass + #p0")
public Book update(Book book) {
    return null;
}

@Override
@Cacheable(value = "usr",key = "targetClass + #p0")
public Book save(Book book) {
    return null;
}

  4. @CacheEvict

  @CacheEvict用來標註需要清除緩存元素的方法或類。該註解用於觸發緩存的清除操作。其屬性有value、key、condition、allEntries 和 beforeInvocation。可以用這些屬性來指定清除的條件。使用方法如下:

@Override
@Cacheable(value = "usr",key = "#p0.id")
public Book save(Book book) {
    return null;
}

@Override
@CacheEvict(value = "usr",key = "#id")
public void delete(int id) {
}

@Override
@CacheEvict(value = "accountCache",allEntries = true)
public void deleteAll() {

}

@Override
@CacheEvict(value = "accountCache",beforeInvocation = true)
public void deleteAll() {

}

  5. @Caching

  註解@Caching用來組合多個註解標簽,有3個屬性:cacheable、put 和 evict,用於指定 @Cacheable、@CachePut 和 @CacheEvict。使用方法如下:

@Override
@Caching(cacheable = {@Cacheable(value = "usr",key = "#p0"),},
         put = {@CachePut(value = "usr",key = "#p0"),},
         evict = {@CacheEvict(value = "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 = "usr",key = "targetClass + #p0")
    public Book update(Book book) {
        return null;
    }

    @Override
    @Caching(cacheable = {@Cacheable(value = "usr",key = "#p0"),},
            put = {@CachePut(value = "usr",key = "#p0"),},
            evict = {@CacheEvict(value = "usr",key = "#p0"),})
    public Book save(Book book) {
        return null;
    }

    @Override
    @CacheEvict(value = "usr",key = "#id")
    public void delete(int id) {
    }

    @Override
    @CacheEvict(value = "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 = "/get",method = RequestMethod.GET,produces = "application/json")
    public Book get(){
        Book book = new Book();
        book.setUsername("拉行啊");
        book.setPassword("123");
        return book;
    }
    @RequestMapping(value = "/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 = "/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 = "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的適用場景

  1. 高併發的讀寫

    Redis特別適合將方法的運行結果放入緩存,以便後續在請求方法時直接去緩存中讀取。對執行耗時,且結果不頻繁變動的SQL查詢的支持極好。

    在高併發的情況下,應盡暈避免請求直接訪問資料庫,這時可以使用Redis進行緩衝操作,讓請求先訪問Redis。

  1. 計數器

    電商網站(APP)商品的瀏覽量、視頻網站(APP)視頻的播放數等數據都會被統計,以便用於運營或產品分析。為了保證數據實時生效,每次瀏覽都得+1,這會導致非常高的併發量。這時可以用Redis提供的incr命令來實現計數器功能,這一切在記憶體中操作,所以性能非常好,非常適用於這些計數場景。

  1. 排行榜

    可以利用Redis提供的有序集合數據類,實現各種複雜的排行榜應用。如京東、淘寶的銷量榜單,商品按時間、銷量排行等。

  1. 分散式會話

    在集群模式下,一般都會搭建以Redis等記憶體資料庫為中心的Session (會活)服務,它不再由容器管理,而是由Session服務及記憶體資料庫管理。

  1. 互動場景

    使用Redis提供的散列、集合等數據結構,可以很方便地實現網站(APP)中的點贊、踩、關註共同好友等社交場景的基本功能。

  1. 最新列表

    Redis可以通過LPUSH在列表頭部插入一個內容ID作為關鍵字,LTRIM可用來限制列表的數量,這樣列表永遠為N個ID,無須查詢最新的列表,直接根據ID查找対應的內容即可。

3. Redis的數據類型

  Redis有5種數據類型,見表11-2。

  

表 11-2

  1. 字元串(string)

    Redis字元串可以包含任意類型的數據、字元、整數、浮點數等。

    一個字元串類型的值的容量有512MB,代表能存儲最大512MB的內容。

    可以使用INCR (DECR、INCRBY)命令來把字元串當作原子計敬器使用。

    使用APPEND命令在字元串後添加內容。

    應用場景:計數器。

  1. 列表(list)

    Redis列表是簡單的字元串列表,按照插入順序排序。可以通過LPUSH、RPUSH命令添加一個元素到列表的頭部或尾部。

    一個列表最多可以包含以”232-1“(4294967295)個元素。

    應用場景:取最新N個數據的操作、消息隊列、刪除與過濾、實時分析正在發生的情況,數據統計與防止垃圾郵件(結合Set )。

  1. 集合(set)

    Redis集合是一個無序的、不允許相同成員存在的字元串合集。

    支持一些伺服器端的命令從現有的集合出發去進行集合運算,如合併(並集:union)、求交(交集intersection)、差集,找出不同元素的操作(共同好友、二度好友)。

    應用場景:Unique操作,可以獲取某段時間內所有數據“排重值”,比如用於共同好友、二度好友、統計獨立IP、好友推薦等。

  1. 散列(hash )

    Redis hash是字元串欄位和字元串值之間的映射,主要用來表示對象,也能夠存儲許多元素。

    應用場景:存儲、讀取、修改用戶屬性。

  1. 有序集合(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的序列化策略。

  

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 函數是基於功能或者邏輯進行聚合的可復用的代碼塊。將一些複雜的、冗長的代碼抽離封裝成多個代碼片段,即函數,有助於提高代碼邏輯的可讀性和可維護性。不同於Python,由於 Go lang是編譯型語言,編譯之後再運行,所以函數的定義順序無關痛癢。 函數聲明 在 Go lang里,函數聲明語法如下: fun ...
  • 《Python高手之路 第3版》|免費下載地址 作者簡介 · · · · · · Julien Danjou 具有12年從業經驗的自由軟體黑客。擁有多個開源社區的不同身份:Debian開發者、Freedesktop貢獻者、GNU Emacs提交者、awesome視窗管理器的創建者以及OpenStac ...
  • 《紅樓夢》作為我國四大名著之一,古典小說的巔峰之作,粉絲量極其龐大,而紅學也經久不衰。所以我們今天通過 Python 來探索下紅樓夢裡那千絲萬縷的人物關係,話不多說,開始整活! 一、準備工作 紅樓夢txt格式電子書一份 金陵十二釵+賈寶玉人物名稱列表 寶玉 nr 黛玉 nr 寶釵 nr 湘雲 nr ...
  • “什麼是IO的多路復用機制?” 這是一道年薪50W的面試題,很遺憾,99%的人都回答不出來。 大家好,我是Mic,一個工作了14年的Java程式員。 今天,給大家分享一道網路IO的面試題。 這道題目的文字回答已經整理到了15W字的面試文檔裡面,大家可以S我領取。 下麵看看高手的回答。 高手: IO多 ...
  • 多商戶商城系統,也稱為B2B2C(BBC)平臺電商模式多商家商城系統。可以快速幫助企業搭建類似拼多多/京東/天貓/淘寶的綜合商城。 多商戶商城系統支持商家入駐加盟,同時滿足平臺自營、旗艦店等多種經營方式。平臺可以通過收取商家入駐費,訂單交易服務費,提現手續費,簡訊通道費等多手段方式,實現整體盈利。 ...
  • 原文連接:https://www.zhoubotong.site/post/67.html Go 標準庫的net/url包提供的兩個函可以直接檢查URL合法性,不需要手動去正則匹配校驗。 下麵可以直接使用ParseRequestURI()函數解析URL,當然這個只會驗證url格式,至於功能變數名稱是否存在或 ...
  • Python帶我起飛——入門、進階、商業實戰_ 免費下載地址 內容簡介 · · · · · · 《Python帶我起飛——入門、進階、商業實戰》針對Python 3.5 以上版本,採用“理論+實踐”的形式編寫,通過大量的實例(共42 個),全面而深入地講解“Python 基礎語法”和“Python ...
  • 1、應用場景 1.1 kafka場景 ​ Kafka最初是由LinkedIn公司採用Scala語言開發,基於ZooKeeper,現在已經捐獻給了Apache基金會。目前Kafka已經定位為一個分散式流式處理平臺,它以 高吞吐、可持久化、可水平擴展、支持流處理等多種特性而被廣泛應用。 ​ Apache ...
一周排行
    -Advertisement-
    Play Games
  • 一:背景 1.講故事 在分析的眾多dump中,經常會遇到各種奇葩的問題,僅通過dump這種快照形式還是有很多問題搞不定,而通過 perfview 這種粒度又太粗,很難找到問題之所在,真的很頭疼,比如本篇的 短命線程 問題,參考圖如下: 我們在 t2 時刻抓取的dump對查看 短命線程 毫無幫助,我根 ...
  • 在日常後端Api開發中,我們跟前端的溝通中,通常需要協商好入參的數據類型,和參數是通過什麼方式存在於請求中的,是表單(form)、請求體(body)、地址欄參數(query)、還是說通過請求頭(header)。 當協商好後,我們的介面又需要怎麼去接收這些數據呢?很多小伙伴可能上手就是直接寫一個實體, ...
  • 許多情況下我們需要用到攝像頭獲取圖像,進而處理圖像,這篇博文介紹利用pyqt5、OpenCV實現用電腦上連接的攝像頭拍照並保存照片。為了使用和後續開發方便,這裡利用pyqt5設計了個相機界面,後面將介紹如何實現,要點包括界面設計、邏輯實現及完整代碼。 ...
  • 思路分析 註冊頁面需要對用戶提交的數據進行校驗,並且需要對用戶輸入錯誤的地方進行提示! 所有我們需要使用forms組件搭建註冊頁面! 平時我們書寫form是組件的時候是在views.py裡面書寫的, 但是為了接耦合,我們需要將forms組件都單獨寫在一個地方,需要用的時候導入就行! 例如,在項目文件 ...
  • 思路分析 登錄頁面,我們還是採用ajax的方式提交用戶數據 唯一需要學習的是如何製作圖片驗證碼! 具體的登錄頁面效果圖如下: 如何製作圖片驗證碼 推導步驟1:在img標簽的src屬性里放上驗證碼的請求路徑 補充1.img的src屬性: 1.圖片路徑 2.url 3.圖片的二進位數據 補充2:字體樣式 ...
  • 哈嘍,兄弟們! 最近有許多小伙伴都在吐槽打工好難。 每天都是執行許多重覆的任務 例如閱讀新聞、發郵件、查看天氣、打開書簽、清理文件夾等等, 使用自動化腳本,就無需手動一次又一次地完成這些任務, 非常方便啊有木有?! 而在某種程度上,Python 就是自動化的代名詞。 今天就來和大家一起學習一下, 用 ...
  • 作者:IT王小二 博客:https://itwxe.com 前面小二介紹過使用Typora+PicGo+LskyPro打造舒適寫作環境,那時候需要使用水印功能,但是小二在升級LskyPro2.x版本發現有很多不如人意的東西,遂棄用LskyPro使用MinIO結合代碼實現自己需要的圖床功能,也適合以後 ...
  • OpenAI Gym是一款用於研發和比較強化學習演算法的工具包,本文主要介紹Gym模擬環境的功能和工具包的使用方法,並詳細介紹其中的經典控制問題中的倒立擺(CartPole-v0/1)問題。最後針對倒立擺問題如何建立控制模型並採用爬山演算法優化進行了介紹,並給出了相應的完整python代碼示例和解釋。要... ...
  • python爬蟲瀏覽器偽裝 #導入urllib.request模塊 import urllib.request #設置請求頭 headers=("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, l ...
  • 前端代碼搭建 主要利用的是bootstrap3中js插件里的模態框版塊 <li><a href="" data-toggle="modal" data-target=".bs-example-modal-lg">修改密碼</a></li> <div class="modal fade bs-exam ...