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. 项目地址

本项目传送门:

此教程会一直更新下去,以为博主写的能够的话,关注一下,也能够更方便下次来学习。


相关文章
相关标签/搜索