• 架构学习——Redis内存数据库学习要点


    目录

    一. 什么是 Redis

    二. Redis 具有如下特点

    三. Redis 具有如下功能

    四. Redis 安装

    五. 五大数据类型介绍

    5.1 STRING

    5.2 LIST

    5.3 HASH

    5.4 SET

    5.5 ZSET

    六. key 相关的命令

    七. Jedis 使用

    7.1 配置

    7.2 Java 端配置

    八.Spring Data Redis 使用

    8.1 Spring Data Redis 介绍

    8.2 环境搭建

    九. SpringBoot整合Redis配合Spring Cache

    十. 框架学习专栏


    一. 什么是 Redis

            Redis 是一个使用 ANSI C 编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。从 2015 年 6 月开始,Redis 的开发由 Redis Labs 赞助,而 2013 年 5 月至 2015 年 6 月期间,其开发由 Pivotal 赞助。在 2013 年 5 月之前,其开发由 VMware 赞助。根据月度排行网站 DB-Engines.com 的数据显示,Redis是 最流行的键值对存储数据库。


    二. Redis 具有如下特点

    • Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,不会造成数据丢失
    • Redis 支持五种不同的数据结构类型之间的映射,包括简单的 key/value 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储
    • Redis 支持 master-slave 模式的数据备份

    三. Redis 具有如下功能

    • 内存存储和持久化:redis 支持异步将内存中的数据写到硬盘上,在持久化的同时不影响继续服务
    • 取最新N个数据的操作,如:可以将最新的 10 条评论的 ID 放在 Redis 的 List 集合里面
    • 数据可以设置过期时间
    • 自带发布、订阅消息系统
    • 定时器、计数器

    四. Redis 安装

            Windows 版 Redis 的安装,整体来非常简单,考虑到 Redis 的大部分使用场景都是在 Linux 上,因此这里我对 Windows 上的安装不做介绍,下面我们主要来看下 Linux 上怎么安装 Redis 。

            环境:

    • CentOS7
    • redis4.0.8

    1.首先下载 Redis,下载地址https://redis.io/,下载获得 redis-4.0.8.tar.gz 后将它放入我们的 Linux 目录 /opt

    2./opt 目录下,对文件进行解压,解压命令: tar -zxvf redis-4.0.8.tar.gz ,如下:

    3.解压完成后出现文件夹:redis-4.0.8,进入到该目录中: cd redis-4.0.8

    4.在 redis-4.0.8 目录下执行 make 命令进行编译

    5.如果 make 完成后继续执行 make install 进行安装

    OK,至此,我们的 redis 就算安装成功了。

    6.在我们启动之前,需要先做一个简单的配置:修改 redis.conf 文件,将里面的 daemonize no 改成 yes,让服务在后台启动,如下:

    7.启动,通过redis-server redis.conf命令启动redis,如下:

    8.测试

    首先我们可以通过 redis-cli 命令进入到控制台,然后通过 ping 命令进行连通性测试,如果看到 pong ,表示连接成功了,如下:

    9.关闭,通过 shutdown 命令我们可以关闭实例,如下:

    OK,至此,我们的 Redis 就安装成功了


    五. 五大数据类型介绍

            redis 中的数据都是以 key/value 的形式存储的,五大数据类型主要是指 value 的数据类型,包含如下五种:

    5.1 STRING

            STRING 是 redis 中最基本的数据类型,redis 中的 STRING 类型是二进制安全的,即它可以包含任何数据,比如一个序列化的对象甚至一个 jpg 图片,要注意的是 redis 中的字符串大小上限是 512M 。

    5.2 LIST

            LIST 是一个简单的字符串列表,按照插入顺序进行排序,我们可以从 LIST 的头部 (LEFT) 或者尾部 (RIGHT) 插入一个元素,也可以从 LIST 的头部(LEFT)或者尾部 (RIGHT) 弹出一个元素。

    5.3 HASH

            HASH 类似于 Java 中的 Map ,是一个键值对集合,在 redis 中可以用来存储对象。

    5.4 SET

            SET 是 STRING 类型的无序集合,不同于 LIST ,SET 中的元素不可以重复。

    5.5 ZSET

            ZSET 和 SET 一样,也是 STRING 类型的元素的集合,不同的是 ZSET 中的每个元素都会关联一个 double 类型的分数,ZSET 中的成员都是唯一的,但是所关联的分数可以重复。

    OK,接下来我们就来看看这五种数据类型要怎么操作。


    六. key 相关的命令

            首先通过 redis-server redis.conf 命令启动 redi s,再通过 redis-cli 命令进入到控制台中,如下:

    6.1 String类型

    存储:set key value 取值:get key 删除:del key 查看所有键:keys *

    1. 127.0.0.1:6379> set key1 "nihao"
    2. OK
    3. 127.0.0.1:6379> set key2 "nihao"
    4. OK
    5. 127.0.0.1:6379> del key1
    6. (integer) 1
    7. 127.0.0.1:6379> keys *
    8. 1) "key2"

    6.2 Hash类型

            相当于一个key对于一个map,map中还有key-value 存储:hset key field value 取值:hget key field

    1. 127.0.0.1:6379> hset zhangsan age 33
    2. (integer) 1
    3. 127.0.0.1:6379> hset zhangsan weight 66
    4. (integer) 1
    5. 127.0.0.1:6379> hget zhangsan age
    6. "33"
    7. 127.0.0.1:6379> hget zhangsan weight
    8. "66"

            查看某个键对应的map里面的所有key:hkeys key 查看某个键对应的map里面的所有的value:hvals key 查看某个键的map:hgetall key

    1. 127.0.0.1:6379>hkeys zhangsan
    2. 1) "age"
    3. 2) "weight"
    4. 127.0.0.1:6379>hvals zhangsan
    5. 1) "33"
    6. 2) "66"
    7. 127.0.0.1:6379>hgetall zhangsan
    8. 1) "age"
    9. 2) "33"
    10. 3) "weight"
    11. 4) "66"

    6.3 List类型

    存储:push,分为lpush list v1 v2 v3 v4 …(左边添加),rpush list v1 v2 v3 v4 …(右边添加)

    1. 127.0.0.1:6379>lpush list1 1 2 3 4
    2. "4"

    取值:pop,分为lpop lpop list(左边取,移除list最左边的值) ,rpop rpop list(右边取,移除list最右边的值)

    1. 127.0.0.1:6379>lpop list1
    2. "4"

    查看list:lrange key 0 2 , lrange key 0 -1表示查看全部

    1. 127.0.0.1:6379>lrange list2 0 2
    2. 1) "wangwu"
    3. 2) "lisi"
    4. 3) "zhangsan"

    6.4 Set类型

    Set中的元素是无序不重复的,出现重复会覆盖 存储:sadd key v1 v2 v3 …

    1. 127.0.0.1:6379>sadd set1 hello world 123
    2. "3"

    移除:srem key v

    1. 127.0.0.1:6379>srem set1 123
    2. "1"

    查看set集合: smembers key

    1. 127.0.0.1:6379>smembers set1
    2. 1) "world"
    3. 2) "hello"

    另外还提供了差集,交集,并集操作 差集:sdiff seta setb(seta中有setb中没有的元素)

    1. 127.0.0.1:6379>sadd set1 hello world nihao haha
    2. "4"
    3. 127.0.0.1:6379>sadd set2 hello2 world2 nihao haha
    4. "4"
    5. 127.0.0.1:6379>sdiff set1 set2
    6. 1) "hello"
    7. 2) "world"

    交集:sinter seta setb

    1. 127.0.0.1:6379>sinter set1 set2
    2. 1) "haha"
    3. 2) "nihao"

    并集:sunion seta setb

    1. 127.0.0.1:6379>sunion set1 set2
    2. 1) "hello2"
    3. 2) "haha"
    4. 3) "world"
    5. 4) "hello"
    6. 5) "world2"

    6.5 ZSet,有序Set

    存储:存储的时候要求对set进行排序,需要对存储的每个value值进行打分,默认排序是分数由低到高。zadd key 分数1 v1 分数2 v2 分数3 v3…

    1. 127.0.0.1:6379>zadd zset1 1 a 3 b 2 c 6 d 5 e 4 f
    2. "6"
    3. 127.0.0.1:6379>zrange zset1 0 -1
    4. 1) "a"
    5. 2) "c"
    6. 3) "b"
    7. 4) "f"
    8. 5) "e"
    9. 6) "d"

    取值:取指定的值 zrem key value(取出后,Set当中对应少一个)

    1. 127.0.0.1:6379>zrem zset1 b
    2. "1"
    3. 127.0.0.1:6379>zrem zset1 a
    4. "1"
    5. 127.0.0.1:6379>zrem zset1 c
    6. "1"

    取(遍历)所有的值(不包括分数):zrange key 0 -1,降序取值用zrevrange key 0 -1

    1. 127.0.0.1:6379>zrange zset1 0 -1
    2. 1) "f"
    3. 2) "e"
    4. 3) "d"
    5. 127.0.0.1:6379>zrevrange zset1 0 -1
    6. 1) "d"
    7. 2) "e"
    8. 3) "f"

    取所有的值(带分数):zrange(zrevrange) key 0 -1 withscores

    1. 127.0.0.1:6379>zrange zset1 0 -1 withscores
    2. 1) "f"
    3. 2) "4"
    4. 3) "e"
    5. 4) "5"
    6. 5) "d"
    7. 6) "6"

    6.6 TTL 命令

    TTL 命令可以查看一个给定 key 的有效时间:

    1. 127.0.0.1:6379> TTL k1
    2. (integer) -1
    3. 127.0.0.1:6379> TTL k2
    4. (integer) -2

    6.7 EXPIRE 命令

    EXPIRE 命令可以给 key 设置有效期,在有效期过后,key 会被销毁。

    1. 127.0.0.1:6379> EXPIRE k1 30
    2. (integer) 1
    3. 127.0.0.1:6379> TTL k1
    4. (integer) 25
    5. 127.0.0.1:6379>

    6.8 PERSIST 命令

    PERSIST 命令表示移除一个 key 的过期时间,这样该 key 就永远不会过期:

    1. 127.0.0.1:6379> EXPIRE k1 60
    2. (integer) 1
    3. 127.0.0.1:6379> ttl k1
    4. (integer) 57
    5. 127.0.0.1:6379> PERSIST k1
    6. (integer) 1
    7. 127.0.0.1:6379> ttl k1
    8. (integer) -1

    七. Jedis 使用

    Redis 的知识我们已经介绍的差不多了,我们来看看如何使用 Java 操作 redis。

    查看 redis 官网,我们发现用 Java 操作 redis,我们有多种解决方案,如下图:

            这里的解决方案有多种,我们采用 Jedis,其他的框架也都大同小异,我这里权当抛砖引玉,小伙伴也可以研究研究其他的方案 。

    7.1 配置

            客户端要能够成功连接上 redis 服务器,需要检查如下三个配置:

    1. 远程 Linux 防火墙已经关闭,以我这里的 CentOS7 为例,关闭防火墙命令 systemctl stop firewalld.service ,同时还可以再补一刀 systemctl disable firewalld.service 表示禁止防火墙开机启动。
    2. 关闭 redis 保护模式,在 redis.conf 文件中,修改 protected 为 no,如下:protected-mode no
    3. 注释掉 redis 的 ip 地址绑定,还是在 redis.conf 中,将 bind:127.0.0.1 注释掉,如下:# bind:127.0.0.1

            确认了这三步之后,就可以远程连接 redis 了。

    7.2 Java 端配置

            上面的配置完成后,我们可以创建一个普通的 JavaSE 工程来测试下了,Java 工程创建成功后,添加 Jedis 依赖,如下:

    1. <dependency>
    2. <groupId>redis.clients</groupId>
    3. <artifactId>jedis</artifactId>
    4. <version>2.9.0</version>
    5. </dependency>

            然后我们可以通过如下一个简单的程序测试一下连接是否成功:

    1. public static void main(String[] args) {
    2. Jedis jedis = new Jedis("192.168.248.128", 6379);
    3. String ping = jedis.ping();
    4. System.out.println(ping);
    5. }

    运行之后,看到如下结果表示连接成功了:

            连接成功之后,剩下的事情就比较简单了,Jedis 类中方法名称和 redis 中的命令基本是一致的,看到方法名小伙伴就知道是干什么的,因此这些我这里不再重复叙述。

            频繁的创建和销毁连接会影响性能,我们可以采用连接池来部分的解决这个问题:

    1. public static void main(String[] args) {
    2. GenericObjectPoolConfig config = new GenericObjectPoolConfig();
    3. config.setMaxTotal(100);
    4. config.setMaxIdle(20);
    5. JedisPool jedisPool = new JedisPool(config, "192.168.248.128", 6379);
    6. Jedis jedis = jedisPool.getResource();
    7. System.out.println(jedis.ping());
    8. }

            这样就不会频繁创建和销毁连接了,在 JavaSE 环境中可以把连接池配置成一个单例模式,如果用了 Spring 容器的话,可以把连接池交给 Spring 容器管理。


    八.Spring Data Redis 使用

    上文我们介绍了 Redis,在开发环境中,我们还有另外一个解决方案,那就是 Spring Data Redis

    8.1 Spring Data Redis 介绍

            Spring Data Redis 是 Spring 官方推出,可以算是 Spring 框架集成 Redis 操作的一个子框架,封装了 Redis 的很多命令,可以很方便的使用 Spring 操作 Redis 数据库,Spring 对很多工具都提供了类似的集成,如 Spring Data MongDB、Spring Data JPA 等, Spring Data Redis 只是其中一种。

    8.2 环境搭建

            要使用 SDR,首先需要搭建 Spring+SpringMVC 环境,由于这个不是本文的重点,因此这一步我直接略过,Spring+SpringMVC 环境搭建成功后,接下来我们要整合 SDR,首先需要添加如下依赖:

    1. <dependency>
    2. <groupId>redis.clientsgroupId>
    3. <artifactId>jedisartifactId>
    4. <version>2.9.0version>
    5. dependency>
    6. <dependency>
    7. <groupId>org.springframework.datagroupId>
    8. <artifactId>spring-data-redisartifactId>
    9. <version>RELEASEversion>
    10. dependency>
    11. <dependency>
    12. <groupId>org.apache.commonsgroupId>
    13. <artifactId>commons-pool2artifactId>
    14. <version>RELEASEversion>
    15. dependency>

    然后创建在 resources 目录下创建 redis.properties 文件作为 redis 的配置文件,如下:

    1. redis.host=192.168.248.128
    2. redis.port=6379
    3. redis.maxIdle=300
    4. redis.maxTotal=600
    5. redis.maxWait=1000
    6. redis.testOnBorrow=true

    在 spring 的配置文件中,添加如下 bean:

    1. <context:property-placeholder location="classpath:redis.properties"/>
    2. <bean class="redis.clients.jedis.JedisPoolConfig" id="poolConfig">
    3. <property name="maxIdle" value="${redis.maxIdle}"/>
    4. <property name="maxTotal" value="${redis.maxTotal}"/>
    5. <property name="maxWaitMillis" value="${redis.maxWait}"/>
    6. <property name="testOnBorrow" value="${redis.testOnBorrow}"/>
    7. bean>
    8. <bean class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" id="connectionFactory">
    9. <property name="hostName" value="${redis.host}"/>
    10. <property name="port" value="${redis.port}"/>
    11. <property name="poolConfig" ref="poolConfig"/>
    12. bean>
    13. <bean class="org.springframework.data.redis.core.RedisTemplate" id="redisTemplate">
    14. <property name="connectionFactory" ref="connectionFactory"/>
    15. <property name="keySerializer">
    16. <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
    17. property>
    18. <property name="valueSerializer">
    19. <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
    20. property>
    21. bean>

            好了,在 Spring 中配置了 redisTemplate 之后,接下来我们就可以在 Dao 层注入 redisTemplate 进而使用了。接下来我们首先创建实体类 User ,注意 User 一定要可序列化:

    1. public class User implements Serializable{
    2. private String username;
    3. private String password;
    4. private String id;
    5. //get/set省略
    6. }

    然后在 Dao 层实现数据的添加和获取,如下:

    1. @Repository
    2. public class HelloDao {
    3. @Autowired
    4. RedisTemplate redisTemplate;
    5. public void set(String key, String value) {
    6. ValueOperations ops = redisTemplate.opsForValue();
    7. ops.set(key, value);
    8. }
    9. public String get(String key) {
    10. ValueOperations ops = redisTemplate.opsForValue();
    11. return ops.get(key).toString();
    12. }
    13. public void setuser(User user) {
    14. ValueOperations ops = redisTemplate.opsForValue();
    15. ops.set(user.getId(), user);
    16. }
    17. public User getuser(String id) {
    18. ValueOperations ops = redisTemplate.opsForValue();
    19. User user = ops.get(id);
    20. System.out.println(user);
    21. return user;
    22. }
    23. }

            SDR 官方文档中对 Redistemplate 的介绍,通过 Redistemplate 可以调用 ValueOperations 和 ListOperations 等等方法,分别是对 Redis 命令的高级封装。但是 ValueOperations 等等这些命令最终是要转化成为 RedisCallback 来执行的。也就是说通过使用 RedisCallback 可以实现更强的功能。

    最后,给大家展示下我的 Service 和 Controller ,如下:

    1. @Service
    2. public class HelloService {
    3. @Autowired
    4. HelloDao helloDao;
    5. public void set(String key, String value) {
    6. helloDao.set(key,value);
    7. }
    8. public String get(String key) {
    9. return helloDao.get(key);
    10. }
    11. public void setuser(User user) {
    12. helloDao.setuser(user);
    13. }
    14. public String getuser(String id) {
    15. String s = helloDao.getuser(id).toString();
    16. return s;
    17. }
    18. }
    1. @Controller
    2. public class HelloController {
    3. @Autowired
    4. HelloService helloService;
    5. @RequestMapping("/set")
    6. @ResponseBody
    7. public void set(String key, String value) {
    8. helloService.set(key, value);
    9. }
    10. @RequestMapping("/get")
    11. @ResponseBody
    12. public String get(String key) {
    13. return helloService.get(key);
    14. }
    15. @RequestMapping("/setuser")
    16. @ResponseBody
    17. public void setUser() {
    18. User user = new User();
    19. user.setId("1");
    20. user.setUsername("深圳");
    21. user.setPassword("sang");
    22. helloService.setuser(user);
    23. }
    24. @RequestMapping(value = "/getuser",produces = "text/html;charset=UTF-8")
    25. @ResponseBody
    26. public String getUser() {
    27. return helloService.getuser("1");
    28. }
    29. }

    测试过程就不再展示了,小伙伴们可以用 POSTMAN 等工具自行测试 。


    九. SpringBoot整合Redis配合Spring Cache

    新建项目添加四个依赖,在springboot2.1.5之后远程连接redis强制要求添加security依赖

    对redis进行配置

    1. # ip
    2. spring.redis.host=127.0.0.1
    3. # 密码
    4. spring.redis.password=12345
    5. # 端口
    6. spring.redis.port=6379
    7. # redis数据库索引
    8. spring.redis.database=0

     User实体类 实现 Serializable 可以被序列化

    1. import java.io.Serializable;
    2. public class User implements Serializable {
    3. private Integer id;
    4. private String name;
    5. private String password;
    6. //getter,setter省略
    7. }

     启动类上添加启用缓存注解

    1. @SpringBootApplication
    2. @MapperScan(basePackages = "org.neuedu.redisboot02.mapper")
    3. @EnableCaching
    4. public class Redisboot02Application {
    5. public static void main(String[] args) {
    6. SpringApplication.run(Redisboot02Application.class, args);
    7. }
    8. }

     UserService

    1. @Service
    2. @Transactional
    3. public class UserService {
    4. @Autowired
    5. UserMapper userMapper;
    6. @Cacheable(value = "user",key = "#id",unless = "#result==null")
    7. public User getUserById(Integer id) {
    8. User user = userMapper.getUserById(id);
    9. System.out.println("test msg");
    10. return user;
    11. }
    12. @CacheEvict(value = "user",key = "#id")
    13. public int deleteById(Integer id) {
    14. return userMapper.deleteById(id);
    15. }
    16. }

     @Cacheable

    该注解的作用是将 value = "user",key = "#id" 值作为组合,作为缓存数据的键值,# 的参数是将方法参数id取出的意思,每次访问该方法时,注解会到缓存中检查是否有value 和 key 值作为组合的键值存在,若存在,则不会调用该方法,也就不会执行mapper的方法,否则就会调用方法,并把返回值存入缓存作为value,key之则是 value = "user",key = "#id"的组合

    unless是缓存条件,上例中是结果不为空时进行缓存

    @CacheEvict

    该注解是删除功能,当访问该方法时,若存在value = "user",key = "#id" 组合而成的键值,就把该缓存数据删除


    十. 框架学习专栏

    https://blog.csdn.net/weixin_53919192/category_11924706.html?spm=1001.2014.3001.5482icon-default.png?t=M7J4https://blog.csdn.net/weixin_53919192/category_11924706.html?spm=1001.2014.3001.5482 

  • 相关阅读:
    改进BERT的中文评论情感分类模型
    PDF格式分析(七十九)——图章、墨迹注释(Stamp、Ink)
    Java二叉树(1)
    Worthington血浆胺氧化酶 (PAO) 说明书
    spring ioc
    【8】c++11新特性 —>右值引用(2)
    3.9 - 正规表达式和正规集 3.10 - 有限自动机
    手把手教你在windows上安装mysql8.0最新版本数据库,保姆级教学
    nginx实现灰度上线(InsCode AI 创作助手)
    离线语音与IoT结合:智能家居发展新增长点
  • 原文地址:https://blog.csdn.net/weixin_53919192/article/details/126466830