Spring Data 教程 - Redis

1. Redis簡介

Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言編寫、支持網絡、可基於內存亦可持久化的日誌型、Key-Value 數據庫,並提供多種語言的API。Redis 是一個高性能的key-value數據庫。 redis的出現,在部分場合能夠對關係數據庫起到很好的補充做用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客戶端,使用很方便。java

Redis支持主從同步。數據能夠從主服務器向任意數量的從服務器上同步,從服務器能夠是關聯其餘從服務器的主服務器。這使得Redis可執行單層樹複製。存盤能夠有意無心的對數據進行寫操做。因爲徹底實現了發佈/訂閱機制,使得從數據庫在任何地方同步樹時,可訂閱一個頻道並接收主服務器完整的消息發佈記錄。同步對讀取操做的可擴展性和數據冗餘頗有幫助。node

redis的key都是字符串String類型,它的value是多樣化的,以下圖:python

redis數據類型 ENCODING返回的編碼 底層對應的數據結構
string int long類型的整數
string embstr embstr編碼的簡單動態字符串
string raw 簡單動態字符串
list ziplist 壓縮列表
list linkedlist 雙向鏈表
hash ziplist 壓縮列表
hash ht 字典
set intset 整數集合
set ht 字典
zset ziplist 壓縮列表
zset skiplist 跳錶

2. Redis的五種數據類型

2.1 字符串對象(String)c++

字符串對象的模型:git

redis底層提供了三種不一樣的數據結構實現字符串對象,根據不一樣的數據自動選擇合適的數據結構。這裏的字符串對象並非指的純粹的字符串,數字也是能夠的。github

  • int:當數據是long類型的整數字符串時,底層使用long類型的整數實現。這個值會直接存儲在字符串對象的ptr屬性中,同時OBJECT ENCODING爲int。web

  • raw:當數據爲長度大於44字節的字符串時,底層使用簡單動態字符串實現,說到這裏就不得不提下redis的簡單隨機字符串(Simple Dynamic String,SDS),SDS有三個屬性,free,len和buf。free存的是還剩多少空間,len存的是目前字符串長度,不包含結尾的空字符。buf是一個list,存放真實字符串數據,包含free和空字符。針對SDS本文不作詳細介紹,歡迎點擊SDS瞭解。redis

  • embstr:當數據爲長度小於44字節的字符串時,底層使用embstr編碼的簡單動態字符串實現。相比於raw,embstr內存分配只須要一次就可完成,分配的是一塊連續的內存空間。spring

2.2 列表對象(List)shell

列表對象的模型:

redis中的列表對象常常被用做消息隊列使用,底層採用ziplist和linkedlist實現。你們使用的時候看成鏈表使用就能夠了。

  • ziplist

    列表對象使用ziplist編碼須要知足兩個要求,一是全部字符串長度都小於設定值值64字節(能夠在配置文件中修改list-max-ziplist-value字段改變)。二是所存元素數量小於設定值512個(能夠在配置文件中修改list-max-ziplist-entries字段改變)。ziplist相似與python中的list,佔用一段連續的內存地址,由此減少指針內存佔用。

    zlbytes:佔內存總數

    zltail:到尾部的偏移量

    zllen:內部節點數

    node:節點

    zlend:尾部標識

    previous_entry_length:前一節點的長度

    encoding:數據類型

    content:真實數據

    遍歷的時候會根據zlbytes和zltail直接找到尾部節點nodeN,而後根據每一個節點的previous_entry_length反向遍歷。增長和刪除節點會致使其餘節點連鎖更新,由於每一個節點都存儲了前一節點的長度。

  • linkedlist

    linkedlist有三個屬性,head,tail和len。head指向鏈表的頭部,tail指向鏈表的尾部,len爲鏈表的長度。

2.3 哈希類型對象(Hash)

哈希類型對象的模型:

redis的value類型hash類型,其實就是map類型,就是在值的位置放一個map類型的數據。你們想詳細瞭解一下,能夠參考一下這篇文章:https://www.jianshu.com/p/658365f0abfc

2.4 集合對象(Set)

集合對象類型的模型:

Set類型的value保證每一個值都不重複。

redis中的集合對象底層有兩種實現方式,分別有整數集合和hashtable。當全部元素都是整數且元素數小於512(可在配置文件中set-max-intset-entries字段配置)時採用整數集合實現,其他狀況都採用hashtable實現。hashtable請移駕上文連接查閱,接下來介紹整數集合intset。intset有三個屬性,encoding:記錄數字的類型,有int16,int32和int64等,length:記錄集合的長度,content:存儲具體數據。具體結構以下圖:

2.5 有序集合對象

有序集合對象(zset)和集合對象(set)沒有很大區別,僅僅是多了一個分數(score)用來排序。

redis中的有序集合底層採用ziplist和skiplist跳錶實現,當全部字符串長度都小於設定值值64字節(能夠在配置文件中修改list-max-ziplist-value字段改變),而且所存元素數量小於設定值512個(能夠在配置文件中修改list-max-ziplist-entries字段改變)使用ziplist實現,其餘狀況均使用skiplist實現,跳躍表的實現原理這裏偷個懶,給你們推薦一篇寫的很是好的博客,點擊查看跳躍表原理

3. Redis的安裝

能夠去官網或者中文網下載Redis。redis的windows版本如今已經不更新了,因此咱們安裝redis的6.0.3版本,這個版本支持的東西不少,在這次教程中,咱們只對redis的五種數據類型作解釋和學習。

官網:https://redis.io/

中文網:https://www.redis.net.cn/

本教程安裝的redis版本爲6.0.3版本,redis使用C語言編寫的,CentOS7的gcc自帶版本爲4.8.5,而redis6.0+須要的gcc版本爲5.3及以上,因此須要升級gcc版本。

下載Linux版本的tar.gz包,解壓之後進入解壓產生的包:

cd redis-6.0.3

發現沒有bin目錄,這裏須要經過make進行安裝。

# 先檢查gcc的環境 
gcc -v 
# 查看gcc版本 
yum -y install centos-release-scl 
# 升級到9.1版本 
yum -y install devtoolset-9-gcc devtoolset-9-gcc- c++ devtoolset-9-binutils 

scl enable devtoolset-9 bash 
#以上爲臨時啓用,若是要長期使用gcc 9.1的話: 
echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile 
# 進入redis解壓文件 
make 
# 6.0的坑,gcc版本 9.0 以上
# 等待完畢

執行完make操做以後,就能夠在redis目錄看到src目錄了。進入src目錄後就能夠看到redis-serverredis-cli

這裏建議將Redis的配置文件複製,保留一份原生的配置文件。

redis的配置你們能夠在網上搜一下經常使用的配置,在這裏給你們推薦一個經常使用的配置,比較詳細:

https://blog.csdn.net/ymrfzr/article/details/51362125

到這裏redis就能夠啓動而且正常訪問了。

注意:必定要將redis的IP地址綁定註釋掉,容許全部的IP地址訪問,否則咱們從Windows訪問就訪問不了。

註釋掉下面的這一行:

同時關閉Redis的服務保護模式,將protected-mode設置爲no。以下:

4. Spring Boot 整合 Redis

  • 4.1 搭建工程,引入依賴

    搭建工程的操做我這裏就不在寫出來了。直接上pom.xml

    <!--springboot父工程-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    <dependencies>
        <!--springboot-web組件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>
        <!--redis整合springboot組件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.3.0.RELEASE</version>
        </dependency>
        <!--lombok組件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
    </dependencies>
  • 4.2 redis的配置

    項目的配置文件,application.yml

    butterflytri:
      host: 127.0.0.1
    server:
      port: 8080 # 應用端口
      servlet:
        context-path: /butterflytri # 應用映射
    spring:
      application:
        name: redis # 應用名稱
      redis:
        host: ${butterflytri.host} # redis地址
        port: 6379 # redis端口,默認是6379
        timeout: 10000 # 鏈接超時時間(ms)
        database: 0 # redis默認狀況下有16個分片,這裏配置具體使用的分片,默認是0
        jedis: # 使用鏈接redis的工具-jedis
          pool:
            max-active: 8 # 鏈接池最大鏈接數(使用負值表示沒有限制) 默認 8
            max-wait: -1 # 鏈接池最大阻塞等待時間(使用負值表示沒有限制) 默認 -1
            max-idle: 8 # 鏈接池中的最大空閒鏈接 默認 8
            min-idle: 0 # 鏈接池中的最小空閒鏈接 默認 0

    另外還有額外的配置類RedisConfig.java

    package com.butterflytri.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.connection.RedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.RedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    /**
     * @author: WJF
     * @date: 2020/5/24
     * @description: RedisConfig
     */
    
    @Configuration
    public class RedisConfig {
    
        /**
         * redis鍵值對的值的序列化方式:通用方式
         * @return RedisSerializer
         */
        private RedisSerializer redisValueSerializer() {
            return new GenericJackson2JsonRedisSerializer();
        }
    
        /**
         * redis鍵值對的健的序列化方式:全部的健都是字符串
         * @return RedisSerializer
         */
        private RedisSerializer redisKeySerializer() {
            return new StringRedisSerializer();
        }
    
        @Bean("redisTemplate")
        public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            redisTemplate.setKeySerializer(redisKeySerializer());
            redisTemplate.setValueSerializer(redisValueSerializer());
            return redisTemplate;
        }
    
    }
  • 4.3 redisTemplate的使用

    value類型的值的CRUD:

    ValueServiceImpl.java

    package com.butterflytri.service.impl;
    
    import com.butterflytri.service.ValueService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    /**
     * @author: WJF
     * @date: 2020/5/27
     * @description: ValueServiceImpl
     */
    @Service
    public class ValueServiceImpl implements ValueService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
        @Override
        public void addValue(String key, Object value) {
            redisTemplate.opsForValue().set(key,value);
        }
    
        @Override
        public Object get(String key) {
            return redisTemplate.opsForValue().get(key);
        }
    
        @Override
        public Object update(String key, Object newValue) {
            return redisTemplate.opsForValue().getAndSet(key,newValue);
        }
    
        @Override
        public void delete(String key) {
            redisTemplate.delete(key);
        }
    }

    List類型的值的CRUD:

    這裏我加了枚舉類型用來控制增長的位置,由於List類型對應的是鏈表。

    ListServiceImpl.java

    package com.butterflytri.service.impl;
    
    import com.butterflytri.enums.OpsType;
    import com.butterflytri.service.ListService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    /**
     * @author: WJF
     * @date: 2020/5/28
     * @description: ListServiceImpl
     */
    @Service
    public class ListServiceImpl implements ListService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
        @Override
        public void addList(String key, List<Object> list, OpsType type) {
            switch (type) {
                case RIGHT:
                    redisTemplate.opsForList().rightPushAll(key, list);
                    break;
                case LEFT:
                    redisTemplate.opsForList().leftPushAll(key, list);
                    break;
                default:
                    throw new RuntimeException("type不能爲null");
            }
        }
    
        @Override
        public void add(String redisKey, Object value, OpsType type) {
            switch (type) {
                case RIGHT:
                    redisTemplate.opsForList().rightPush(redisKey, value);
                    break;
                case LEFT:
                    redisTemplate.opsForList().leftPush(redisKey, value);
                    break;
                default:
                    throw new RuntimeException("type不能爲null");
            }
        }
    
        @Override
        public List<Object> get(String key) {
            return redisTemplate.opsForList().range(key, 0, -1);
        }
    
        @Override
        public Object update(String key, Object value, Integer index) {
            Object obj = redisTemplate.opsForList().index(key, index);
            redisTemplate.opsForList().set(key,index,value);
            return obj;
        }
    
        @Override
        public void delete(String key) {
            redisTemplate.delete(key);
        }
    
        @Override
        public void deleteValue(String redisKey, OpsType type) {
            switch (type) {
                case RIGHT:
                    redisTemplate.opsForList().rightPop(redisKey);
                    break;
                case LEFT:
                    redisTemplate.opsForList().leftPop(redisKey);
                    break;
                default:
                    throw new RuntimeException("type不能爲null");
            }
        }
    }

    Hash類型的值的CRUD:

    hash類型是咱們使用最經常使用的類型。

    HashServiceImpl.java:

    package com.butterflytri.service.impl;
    
    import com.butterflytri.service.HashService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.Map;
    
    /**
     * @author: WJF
     * @date: 2020/5/28
     * @description: HashServiceImpl
     */
    @Service
    public class HashServiceImpl implements HashService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
        @Override
        public void addHashAll(String key, Map<String, Object> value) {
            redisTemplate.opsForHash().putAll(key, value);
        }
    
        @Override
        public void addHash(String redisKey, String key, Object value) {
            redisTemplate.opsForHash().put(redisKey, key, value);
        }
    
        @Override
        public Object get(String redisKey, String key) {
            return redisTemplate.opsForHash().get(redisKey, key);
        }
    
        @Override
        public Object update(String redisKey, String key, Object value) {
            Object obj = this.get(redisKey, key);
            this.delete(redisKey,key);
            redisTemplate.opsForHash().put(redisKey, key, value);
            return obj;
        }
    
        @Override
        public void delete(String redisKey, String key) {
            redisTemplate.opsForHash().delete(redisKey, key);
        }
    
        @Override
        public void deleteAll(String redisKey) {
            redisTemplate.delete(redisKey);
        }
    }

    Set的值的CRUD:

    package com.butterflytri.service.impl;
    
    import com.butterflytri.service.SetService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.Set;
    
    /**
     * @author: WJF
     * @date: 2020/5/28
     * @description: SetServiceImpl
     */
    @Service
    public class SetServiceImpl implements SetService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
    
        @Override
        public void addAll(String key, Set<Object> set) {
            redisTemplate.opsForSet().add(key,set);
        }
    
        @Override
        public void add(String key, Object value) {
            redisTemplate.opsForSet().add(key,value);
        }
    
        @Override
        public Set<Object> findAll(String key) {
            return redisTemplate.opsForSet().members(key);
        }
    
        @Override
        public void deleteValue(String key, Object value) {
            redisTemplate.opsForSet().remove(key,value);
        }
    
        @Override
        public void delete(String key) {
            redisTemplate.delete(key);
        }
    }

    ZSet類型的值的CRUD:

    package com.butterflytri.service.impl;
    
    import com.butterflytri.service.SortedSetService;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.LinkedHashSet;
    
    /**
     * @author: WJF
     * @date: 2020/5/28
     * @description: SortedSetServiceImpl
     */
    @Service
    public class SortedSetServiceImpl implements SortedSetService {
    
        @Resource
        private RedisTemplate<String, Object> redisTemplate;
    
        @Override
        public void add(String key, String value, Double score) {
            redisTemplate.opsForZSet().add(key, value, score);
        }
    
        @Override
        public LinkedHashSet<Object> findAll(String key) {
            return (LinkedHashSet<Object>) redisTemplate.opsForZSet().range(key,0,-1);
        }
    
        @Override
        public Long count(String key, Double scoreFrom, Double scoreTo) {
            return redisTemplate.opsForZSet().count(key,scoreFrom,scoreTo);
        }
    
        @Override
        public LinkedHashSet<Object> findByScore(String key, Double scoreFrom, Double scoreTo) {
            return (LinkedHashSet<Object>) redisTemplate.opsForZSet().rangeByScore(key,scoreFrom,scoreTo);
        }
    
        @Override
        public Long rank(String key, Object value) {
            return redisTemplate.opsForZSet().rank(key,value);
        }
    
        @Override
        public void remove(String key, String value) {
            redisTemplate.opsForZSet().remove(key,value);
        }
    
        @Override
        public void delete(String key) {
            redisTemplate.delete(key);
        }
    
    }

    redis的Java客戶端有不少,在這裏咱們使用的是jedis,還有一個很好的Java語言的客戶端叫lettuce,你們能夠去了解一下,Spring從不重複造輪子,只會簡化輪子的使用,redisTemplate就是一個超級簡單的使用實現。到這裏redis整合Spring Boot 就結束了。

5. 項目地址

本項目傳送門:

此教程會一直更新下去,以爲博主寫的能夠的話,關注一下,也能夠更方便下次來學習。


相關文章
相關標籤/搜索