springboot-redis

1Nosql定义和分类

1.1什么是NoSql

  • NoSql,叫非关系型数据库,它的全名Not only sql。
  • 为了解决高并发、高可用、高可扩展,大数据存储等一系列问题而产生的数据库解决方案,就是NoSql。它不能替代关系型数据库,只能作为关系型数据库的一个良好补充。

1.2NoSql的分类

1.2.1键值(Key-Value)存储数据库

相关产品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB

典型应用: 内容缓存,主要用于处理大量数据的高访问负载。

数据模型: 一系列键值对

优势: 快速查询

劣势: 存储的数据缺少结构化

1.2.2列存储数据库

相关产品:Cassandra, HBase, Riak

典型应用:分布式的文件系统

数据模型:以列簇式存储,将同一列数据存在一起

优势:查找速度快,可扩展性强,更容易进行分布式扩展

 劣势:功能相对局限

1.2.3文档型数据库

相关产品:CouchDB、MongoDB

典型应用:Web应用(与Key-Value类似,Value是结构化的)

数据模型: 一系列键值对

 优势:数据结构要求不严格

 劣势: 查询性能不高,而且缺乏统一的查询语法

1.2.4图形(Graph)数据库

相关数据库:Neo4J、InfoGrid、Infinite Graph

典型应用:社交网络

数据模型:图结构

优势:利用图结构相关算法。

劣势:需要对整个图做计算才能得出结果,不容易做分布式的集群方案。

2Redis定义,历史和应用场景

2.1什么是redis

Redis是使用c语言开发的一个高性能键值数据库。Redis可以通过一些键值类型来存储数据。

键值类型:

String字符类型

map散列类型hash

list列表类型

set集合类型

sortedset有序集合类型

2.2redis历史发展

       2008年,意大利的一家创业公司Merzia推出了一款基于MySQL的网站实时统计系统LLOOGG,然而没过多久该公司的创始人 Salvatore Sanfilippo便 对MySQL的性能感到失望,于是他决定亲自为LLOOGG量身定做一个数据库,并于2009年开发完成,这个数据库就是Redis。 不过Salvatore Sanfilippo并不满足只将Redis用于LLOOGG这一款产品,而是希望更多的人使用它,于是在同一年Salvatore Sanfilippo将Redis开源发布,并开始和Redis的另一名主要的代码贡献者Pieter Noordhuis一起继续着Redis的开发,直到今天。

       Salvatore Sanfilippo自己也没有想到,短短的几年时间,Redis就拥有了庞大的用户群体。Hacker News在2012年发布了一份数据库的使用情况调查,结果显示有近12%的公司在使用Redis。国内如新浪微博、街旁网、知乎网,国外如GitHub、Stack Overflow、Flickr等都是Redis的用户。

       VMware公司从2010年开始赞助Redis的开发, Salvatore Sanfilippo和Pieter Noordhuis也分别在3月和5月加入VMware,全职开发Redis。

2.3redis的应用场景

缓存(数据查询、短连接、新闻内容、商品内容等等)。(最多使用

分布式集群架构中的session分离。

聊天室的在线好友列表。

任务队列。(秒杀、抢购、12306等等)

应用排行榜。

网站访问统计。

数据过期处理(可以精确到毫秒)

3Redis下载和安装

3.1windows版下载和安装

 window版下载地址:https://github.com/MicrosoftArchive/redis/releases

下载Redis For  window X64.zip,解压到指定目录

3.1.1Redis的目录结构

Redis.windows.conf:redis的配置文件。文件内可以声明redis的端口号,database的数量,密码,是否后台运行,持久化机制,日志等信息。

Redis-server.exe:redis服务端,可以启动redis服务。

Redis-cli.exe: redis自带客户端,启动以后即可连接服务端,通过以命令的形式向redis服务中存取数据,也可以关闭redis服务。

3.1.2启动redis服务端

双击 redis-server.exe ,启动成功,出现如下界面。端口号6379,pid:1236,如果关闭当前窗口,相当于关闭redis服务。

或者以命令行的方式启动redis,在当前目录下输入redis-server即可启动redis服务(配置要写)

3.1.3启动redis客户端

双击redis-cli.exe即可启动客户端:如下图表示,则已经连上服务端,可以通过命令存取数据了。

如果服务端设置了密码,在运行客户端连接服务端时,需要加上密码

./redis-cli -a 123456  -------123456为密码

3.1.4图形化界面客户端

RedisDesktopManager以图形化界面的方式操作redis中的数据。安装redis桌面管理工具。

建立连接:

输入名称,主机ip,默认端口号6379,即可连接redis服务器。

可以测试连接,如果连接成功,会有如下弹框:

Redis默认有16个数据库,如果不指定,默认使用database0

向第一个数据库中添加,修改,删除数据。

3.1.5指定配置启动redis服务

Redis启动时可以不指定配置文件,会使用默认配置启动。也可以指定配置文件。如果我们修改了配置文件的内容,希望指定以某个配置文件启动,则使用如下方法启动

复制配置文件redis.windows.conf,改名为redis.conf,修改使用密码123456登录。

以该配置文件运行redis服务:

此时,再通过图形化客户端连接服务时,必须指定密码才可以,否则会连接失败。

3.2Linux版下载和安装

3.2.1下载

官网:https://redis.io/download,选择稳定版本。

3.2.2安装

1.解压

通过xftp把redis安装包上传到指定文件夹。解压:

tar -zxvf redis-6.0.6.tar.gz

2.安装

由于redis依赖c语言环境,所以先安装gcc

[root@localhost ~]# yum install gcc

如果是线上下载安装包的话,先进入目录  usr/local,下载安装包

[root@localhost local]# wget http://download.redis.io/releases/redis-6.0.6.tar.gz

解压

[root@localhost local]# tar -xvf redis-6.0.6.tar.gz

安装好了c语言环境以后,需要编译redis,进入解压后的目录

[root@localhost local]# cd /usr/local/redis-6.0.6/

编译

[root@localhost local]# make

安装,如果不指明安装路径,就会在当前路径下安装,指明安装路径,会在指明的路径下生成bin文件夹,bin里面是redis的命令

[root@localhost redis-6.0.1]# make PREFIX=/usr/local/redis-6.0.6 install

进入bin

注意:如果在编译的时候报错如下:等等,太长了,不列举了。

make[1]: *** [server.o] 错误 1

make[1]: 离开目录“/usr/redis-6.0.6/src”

make: *** [all] 错误 2

server.c:2402:11: 错误:‘struct redisServer’没有名为‘assert_file’的成员

     server.assert_file = "<no file>";

           ^

server.c:2403:11: 错误:‘struct redisServer’没有名为‘assert_line’的成员

     server.assert_line = 0;

           ^

server.c:2404:11: 错误:‘struct redisServer’没有名为‘bug_report_start’的成员

     server.bug_report_start = 0;

           ^

解决办法:升级gcc版本

[root@localhost redis-6.0.6]# gcc -v                             # 查看gcc版本

[root@localhost redis-6.0.6]# yum -y install centos-release-scl  # 升级到9.1版本

[root@localhost redis-6.0.6]# yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils

[root@localhost redis-6.0.6]# scl enable devtoolset-9 bash

以上为临时启用,如果要长期使用gcc 9.1的话:

[root@localhost redis-6.0.6]# echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile

在执行编译就没有问题了,安装成功,会提示:

执行make test,可能会出现如下错误:

[root@localhost redis-6.0.6]# make test

cd src && make test

make[1]: 进入目录“/usr/redis-6.0.6/src”

    CC Makefile.dep

make[1]: 离开目录“/usr/redis-6.0.6/src”

make[1]: 进入目录“/usr/redis-6.0.6/src”

You need tcl 8.5 or newer in order to run the Redis test

make[1]: *** [test] 错误 1

make[1]: 离开目录“/usr/redis-6.0.6/src”

make: *** [test] 错误 2

解决办法:

[root@localhost redis-6.0.6]# yum install tcl

[root@localhost redis-6.0.6]# make test

重新测试成功。

3.2.3运行redis

以某个配置文件启动redis服务,一定要注意配置文件的路径

3.2.4后台启动

上面redis的启动方式,是前端启动,一关闭客户端,redis的服务也就停掉了,所以这种启动方式非常不友好。我们可以修改配置文件中的启动方式:

[root@localhost redis-6.0.6]# vim redis.conf

进到redis.conf文件里,然后找到daemonize no把no改为yes

启动的时候指定修改之后的配置文件即可。

3.2.5查看是否启动成功

3.2.6关闭redis服务

或者:

如果redis设置了密码,则以下面方式关闭,123456为密码

3.2.7使用桌面管理工具连接Linux redis

修改redis配置文件,注释掉bind 127.0.0.1

保护模式关闭:

 

设置密码:

3.2.8以服务方式启动redis

  1. 把redis加入service服务

vim /lib/systemd/system/redis.service

  1. 写入

[Unit]

Description=redis

After=network.target

 

[Service]

Type=forking

PIDFile=/var/run/redis_6379.pid

ExecStart=/usr/local/redis-6.0.6/src/redis-server /usr/local/redis-6.0.6/etc/redis.conf

ExecReload=/bin/kill -s HUP $MAINPID

ExecStop=/bin/kill -s QUIT $MAINPID

PrivateTmp=true

 

[Install]

WantedBy=multi-user.target

注意路径问题,以及PIDFile的路径对应的是redis-6.0.6/redis.conf里面的PIDFile

保存,退出。

  1. 运行以下

[root@localhost redis-6.0.6]# systemctl enable redis.service          # 加入开机启动

 

[root@localhost redis-6.0.6]# systemctl is-enabled redis.service      # 查看开机是否启动成功

enabled

 

[root@localhost redis-6.0.6]# systemctl start redis                 #开启redis服务

 

[root@localhost redis-6.0.6]# systemctl status redis            //查看redis运行状态

3.3清缓存命令

flushall 

把缓存键值对清空。

4Redis的String数据类型的赋值取值删除

4.1命令

4.1.1赋值

语法:SET key value

4.1.2取值

语法:GET key

4.1.3取值并赋值

语法:GETSET key value

4.1.4设置/获取多个键值

语法:

MSET key value [key value …]

MGET key [key …]

4.1.5删除

语法:DEL key

4.1.6数值增减

  • 递增数字

当存储的字符串是整数时,Redis提供了一个实用的命令INCR(increate),其作用是让当前键值递增,并返回递增后的值。

语法:INCR key

  • 增加指定的整数

语法:INCRBY key increment

  • 递减数值

语法:DECR key

 

  • 减少指定的整数

语法:DECRBY key decrement

5Redis的Hash数据类型的赋值取值删除

散列类型

5.1使用string的问题

       假设有User对象以JSON序列化的形式存储到Redis中,User对象有id,username、password、age、name等属性,存储的过程如下:

保存、更新:

User对象➡️json(string)➡️redis

如果在业务上只是更新age属性,其他的属性并不做更新我应该怎么做呢? 如果仍然采用上边的方法在传输、处理时会造成资源浪费,下边讲的hash可以很好的解决这个问题。

5.2redis hash介绍

       hash叫散列类型,它提供了字段和字段值的映射。字段值只能是字符串类型,不支持散列类型、集合类型等其它类型。如下:

5.3命令

5.3.1赋值

HSET命令不区分插入和更新操作,当执行插入操作时HSET命令返回1,当执行更新操作时返回0。

  • 一次只能设置一个字段值

语法:HSET key field value    

 

  • 一次可以设置多个字段值

语法:HMSET key field value [field value ...]         

     

  • 当字段不存在时赋值,类似HSET,区别在于如果字段存在,该命令不执行任何操作

语法:HSETNX key field value

5.3.2取值

  • 一次只能获取一个字段值

语法:HGET key field     

              

  • 一次可以获取多个字段值

语法:HMGET key field [field ...]              

           

  • 获取所有字段值

语法:HGETALL key

 

5.3.3删除字段

可以删除一个或多个字段,返回值是被删除的字段个数

语法:HDEL key field [field ...]

5.3.4增加数字

语法:HINCRBY key field increment

例:将用户的年龄加1

 6Redis的List数据类型的赋值取值删除

Redis的list是采用来链表来存储的,所以对于redis的list数据类型的操作,是操作list的两端数据来操作的。

6.2命令

6.2.1向列表两端增加元素

  • 向列表左边增加元素

语法:LPUSH key value [value ...]

  • 向列表右边增加元素

语法:RPUSH key value [value ...]

6.2.2查看列表

LRANGE命令是列表类型最常用的命令之一,获取列表中的某一片段,将返回start、stop之间的所有元素(包含两端的元素),索引从0开始。索引可以是负数。

-1”代表最后边的一个元素

语法:LRANGE key start stop

6.2.3从列表两端弹出元素

LPOP命令从列表左边弹出一个元素,会分两步完成:

第一步是将列表左边的元素从列表中移除

第二步是返回被移除的元素值。

语法:

LPOP key

RPOP key

6.2.4获取列表中元素的个数

语法:LLEN key

7Redis的Set数据类型的赋值取值删除

集合类型

集合类型:无序、不可重复

列表类型:有序、可重复

7.1命令

7.1.1增加/删除元素

语法:SADD key member [member ...]

语法:SREM key member [member ...]

7.1.2获得集合中的所有元素

语法:SMEMBERS key

(无序、不可重复)

7.1.3判断元素是否在集合中

语法:SISMEMBER key member

7.2运算命令

7.2.1集合的差集运算 A-B

属于A并且不属于B的元素构成的集合。

语法:SDIFF key [key ...]

7.2.2集合的交集运算 A ∩ B

属于A且属于B的元素构成的集合。

语法:SINTER key [key ...]

7.2.3集合的并集运算 A ∪ B

属于A或者属于B的元素构成的集合

语法:SUNION key [key ...]

 

8Redis的SortedSet数据类型的赋值取值删除

8.1Sortedset

  • Sortedset又叫zset
  • Sortedset是有序集合,可排序的,但是唯一
  • Sortedset和set的不同之处,是会给set中的元素添加一个分数,然后通过这个分数进行排序。

8.2命令

8.2.1增加元素

  • 向有序集合中加入一个元素和该元素的分数,如果该元素已经存在则会用新的分数替换原有的分数。
  • 返回值是新加入到集合中的元素个数,不包含之前已经存在的元素。

语法:ZADD key score member [score member ...]

8.2.2获取元素的分数

语法:ZSCORE key member

8.2.3删除元素

  • 移除有序集key中的一个或多个成员,不存在的成员将被忽略。
  • 当key存在但不是有序集类型时,返回一个错误。

语法:ZREM key member [member ...]

8.2.4获得排名在某个范围的元素列表

  • 获得排名在某个范围的元素列表
  • 按照元素分数从小到大的顺序返回索引从start到stop之间的所有元素(包含两端的元素)

语法:ZRANGE key start stop [WITHSCORES]           

       

  • 按照元素分数从大到小的顺序返回索引从start到stop之间的所有元素(包含两端的元素)

语法:ZREVRANGE key start stop [WITHSCORES]          

 

  • 如果需要获得元素的分数的可以在命令尾部加上WITHSCORES参数

8.2.5获取元素的排名

  • 从小到大

语法:ZRANK key member

 

  • 从大到小

语法:ZREVRANK key member

9Keys命令

9.1常用命令

9.1.1keys

返回满足给定pattern 的所有key

9.1.2exists

确认一个key 是否存在

示例:从结果来看,数据库中不存在listA这个key,但是setA这个key 是存在的

9.1.3del

删除一个key

9.1.4rename

重命名key

示例:setA成功的被我们改名为setA_new 了

9.1.5type

返回值的类型

示例:这个方法可以非常简单的判断出值的类型

9.1.6设置key的生存时间

Redis在实际使用过程中更多的用作缓存,然而缓存的数据一般都是需要设置生存时间的

即:到期后数据销毁。

EXPIRE key seconds                  设置key的生存时间(单位:秒)key在多少秒后会自动删除

TTL key                             查看key剩余的生存时间

PERSIST key                       清除生存时间  -1

PEXPIRE key milliseconds  生存时间设置单位为:毫秒

  • -1:清除生存时间,redis一直存在该key
  • -2:到期,redis没有该key
  • 正整数:剩余的生存时间

例子:

10SpringBoot整合Redis

10.1新建SpringBoot工程,引入Web,Redis的场景启动器

(1)方式一:创建项目时,勾选

(2)方式二:创建项目后,自行加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

如果网络不稳定,不能下载依赖,删掉下面的文件夹,再试试

10.2application.yml配置redis地址

spring.redis.host

#配置redis地址ip和密码
spring:
  redis:
    host: 127.0.0.1
    password: 123456

10.3在使用处注入StringRedisTemplate或者RedisTemplate

  • 有依赖后,springboot自动装配
  • 一般在spring.factories里,2.7.1版本在别的位置
  • StringRedisTemplate可直接通过@Autowired根据类型进行自动装配

10.3.1StringRedisTemplate处理字符串相关操作

10.3.1.1 Redis的String数据类型

 

package com.tjetc;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import java.util.HashMap;
import java.util.Map;
@SpringBootTest
class ApplicationTests {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Test
    public void testString() {
        System.out.println(stringRedisTemplate);
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        opsForValue.set("k1", "v1");
        opsForValue.set("k2", "v2");
        String v1 = opsForValue.get("k1");
        System.out.println(v1);
        //存储多对key和value
        Map<String, String> map = new HashMap<>();
        map.put("k3", "v3");
        map.put("k4", "v4");
        opsForValue.multiSet(map);
    }
}

10.3.1.2 Redis的Hash数据类型的赋值取值

@Test
public void testHash() {
    //HashOperations操作hash类型的数据
    HashOperations<String, Object, Object> opsForHash = stringRedisTemplate.opsForHash();
    //存储单个字段名和字段值
    opsForHash.put("user","username","kelly");
    opsForHash.put("user","age","21");
    //存储过程字段名和字段值
    Map<String, String> map = new HashMap<>();
    map.put("sex","female");
    map.put("email","yj@163.com");
    opsForHash.putAll("user",map);
    //获取单个值
    Object o = opsForHash.get("user", "username");
    System.out.println("username="+o);
    //一次获取多个值
    List<Object> hashKeys = Arrays.asList("username", "age", "sex", "email");
    List<Object> list = opsForHash.multiGet("user", hashKeys);
    System.out.println("user的多个hash值"+list);
}

 

10.3.1.3 Redis的List数据类型的赋值取值

@Test
public void testList() {
    ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
    //向列表左边增加元素
    opsForList.leftPush("list", "1");
    opsForList.leftPush("list", "2");
    //向列表左边增加多个元素
    opsForList.leftPushAll("list", "3", "4");
    //向列表右边增加元素
    opsForList.rightPush("list", "5");
    opsForList.rightPush("list", "6");
    //向列表右边增加多个元素
    opsForList.rightPushAll("list", "7", "8");
    //查看列表
    List<String> list = opsForList.range("list", 0, -1);
    System.out.println(list);
    //从列表右边弹出一个元素
    String rightLast = opsForList.rightPop("list");
    System.out.println("从列表右边弹出一个元素:" + rightLast);
    //再次查看列表
    List<String> list1 = opsForList.range("list", 0, -1);
    System.out.println(list1);
}

 

再次运行方法,重复添加

10.3.1.4 Redis的Set数据类型的赋值取值

@Test
public void testSet() {
    SetOperations<String, String> opsForSet = stringRedisTemplate.opsForSet();
    //增加元素
    opsForSet.add("setA", "a", "b", "c", "a");
    Set<String> setA = opsForSet.members("setA");
    System.out.println("setA:" + setA);
    opsForSet.add("setB", "b", "c", "d", "b");
    Set<String> setB = opsForSet.members("setB");
    System.out.println("setB:" + setB);
    //差集
    Set<String> differenceA = opsForSet.difference("setA", "setB");
    System.out.println("属于A并且不属于B的元素构成的集合:" + differenceA);
    Set<String> differenceB = opsForSet.difference("setB", "setA");
    System.out.println("属于B并且不属于A的元素构成的集合:" + differenceB);
    //交集
    Set<String> intersect = opsForSet.intersect("setA", "setB");
    System.out.println("属于A且属于B的元素构成的集合:" + intersect);
    //并集
    Set<String> union = opsForSet.union("setA", "setB");
    System.out.println("属于A或者属于B的元素构成的集合:" + union);
}

 

10.3.1.5 Redis的SortedSet(ZSet)数据类型的赋值取值

@Test
public void testZSet() {
    ZSetOperations<String, String> opsForZSet = stringRedisTemplate.opsForZSet();
    //增加单个元素
    opsForZSet.add("score", "kelly", 100);
    //增加多个元素
    Set<ZSetOperations.TypedTuple<String>> set = new HashSet<>();
    DefaultTypedTuple<String> typedTupleM = new DefaultTypedTuple("marry", (double) 90);
    DefaultTypedTuple<String> typedTupleJ = new DefaultTypedTuple("jack", (double) 80);
    set.add(typedTupleM);
    set.add(typedTupleJ);
    opsForZSet.add("score", set);
    //获取元素的分数
    Set<ZSetOperations.TypedTuple<String>> score = opsForZSet.rangeWithScores("score", 0, -1);
    System.out.println(score);
}

 

10.3.2RedisTemplate

处理对象相关操作

10.3.2.1redisTemplate默认如果保存对象,使用jdk序列化机制

package com.tjetc.entity;
import java.io.Serializable;
/**
 * 自定义实体类,目的是要序列化到Redis中
 */
public class User implements Serializable {
    private Long id;
    private String username;
    private String password;
    public Long getId() {return id; }
    public void setId(Long id) { this.id = id;}
    public String getUsername() {return username;}
    public void setUsername(String username) {this.username = username;}
    public String getPassword() {return password; }
    public void setPassword(String password) {this.password = password;}
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
package com.tjetc;
import com.tjetc.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
@SpringBootTest
public class RedisTemplateTests {
    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    public void test() {
        //创建一个user对系
        User user = new User();
        user.setId(1L);
        user.setUsername("kelly");
        user.setPassword("9588");
        /*ValueOperations opsForValue = redisTemplate.opsForValue();
        opsForValue.set("u", user);
        User user1 = (User)opsForValue.get("u");*/
        ValueOperations<Object, User> opsForValue = redisTemplate.opsForValue();
        //对象序列化二进制数据后存储到redis中
        opsForValue.set("u", user);
        //获取user
        User user1 = opsForValue.get("u");
        System.out.println(user1);
    }
}

10.3.2.2改变jdk的序列化规则

①在配置类中配置自定义序列化规则
package com.tjetc.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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfiguration {
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
        //创建RedisTemplate对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        //设置连接工厂
        template.setConnectionFactory(factory);
        //创建GenericJackson2JsonRedisSerializer对象,序列化为json格式
        GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
        //template对象设置value的序列化方式
        template.setValueSerializer(serializer);
        //template对象设置key的序列化方式
        template.setKeySerializer(new StringRedisSerializer());
        return template;
    }
}
②使用
package com.tjetc;
import com.tjetc.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
@SpringBootTest
public class RedisConfigurationTemplateTests {
    @Autowired
    private RedisTemplate<String, User> redisTemplate;
    @Test
    public void test() {
        //创建一个user对系
        User user = new User();
        user.setId(1L);
        user.setUsername("kelly");
        user.setPassword("9588");
        ValueOperations<String, User> opsForValue = redisTemplate.opsForValue();
        //对象序列化二进制数据后存储到redis中
        opsForValue.set("u", user);
        //获取user
        User user1 = opsForValue.get("u");
        System.out.println(user1);
    }
}

11持久化

11.1Redis持久化概述

持久化的功能:Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘;当下次Redis重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置。

Redis持久化分为RDB持久化和AOF持久化:前者将当前数据保存到硬盘,后者则是将每次执行的写命令保存到硬盘(类似于MySQLbinlog);由于AOF持久化的实时性更好,即当进程意外退出时丢失的数据更少,因此AOF是目前主流的持久化方式,不过RDB持久化仍然有其用武之地。

下面依次介绍RDB持久化和AOF持久化;由于Redis各个版本之间存在差异,如无特殊说明,以Redis3.0为准。

11.2RDB持久化

# 转储数据库的文件名

默认方式,不需要进行配置,默认就使用这种机制。

在一定的间隔时间中,检测key的变化情况,然后持久化数据

1.编辑redis.windows.conf配置文件

#   after 900 sec (15 min) if at least 1 key changed

#   900 秒(15 分钟)后,如果至少 1 个键更改

save 900 1

#   after 300 sec (5 min) if at least 10 keys changed

#   300 秒(5 分钟)后,如果至少有 10 个键被更改

save 300 10

#   after 60 sec if at least 10000 keys changed

#   如果至少有 10000 个键被更改,则在 60 秒后

save 60  10000

如果我们将配置该成如下形式:

save 900 1

save 300 10

save 10  5:在10秒之后,如果有5个键发生了改变,则执行持久化

2.重启服务器,并指定配置文件

  • C:\Users\hzw\Documents\Java\software\Redis-x64-3.0.503>redis-server.exe redis.windows.conf

3.启动客户端

127.0.0.1:6379> set username 1

OK

127.0.0.1:6379> set username 2

OK

127.0.0.1:6379> set username 3

OK

127.0.0.1:6379> set username 4

OK

127.0.0.1:6379> set username 5

OK

上述操作在10秒内完成。这时在当前目录下会出现一个rdb文件。

关闭服务器和客户端。

4.重新启动服务器和客户端,不需要指定配置文件。在客户端直接获取username,结果如下:

127.0.0.1:6379> get username

"5"

11.3AOF持久化

日志记录的方式,可以记录每一条命令的操作。可以每一次命令操作后,持久化数据。

1.编辑redis.windows.conf配置文件

appendonly no(关闭aof) --> appendonly yes (开启aof

  AOF相关配置:

# appendfsync always  每一次操作都进行持久化

appendfsync everysec  每一秒进行一次持久化,默认方式

# appendfsync no      不进行持久化

2.重启服务器,指定配置文件

3.启动客户端,1秒持久化一次

4.关闭并重启服务器(指定配置文件)和客户端,在客户端获取,结果如下:

Redis为什么这么快?

1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于 HashMap,HashMap 的优势就是查找和操作的时间复杂度都是O(1);
2、数据结构简单,对数据操作也简单,Redis 中的数据结构是专门进行设计的;
3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
4、使用多路 I/O 复用模型,非阻塞 IO;
5、使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis 直接自己构建了 VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

posted @ 2022-07-12 09:00  carat9588  阅读(182)  评论(0编辑  收藏  举报