Redis (Super invincible, serious and easy to use, Wanzi collection!!!!)

Redis

foreword

Relational database : Sql Server MySql Oracle...

Relationship: the connection between tables

Traditional relational databases are stored on hard drives, and relationships are based on business.

Problems with relational databases :

  1. The relational database is stored on the hard disk, and the IO performance of the disk is low, which cannot meet the high-frequency access and high-efficiency applications, especially the sea

The case of high concurrent access by a large number of users

  1. Relational database table relationships are complex, query efficiency is low, and it is not easy to expand (table connection query cannot exceed 7 tables)

cache : (cache) a data storage area that can be accessed at high speed and used for temporary storage

Caching usage occasions

Cache is generally used in occasions where the same data is frequently read in a short period of time, put the data with high read frequency into the cache, and take the data directly from the cache to improve efficiency

NOSQL database

NOSQL (Not only SQL), that is, "not just SQL", generally refers to non-relational databases.

NOSQL does not rely on business logic storage, but stores in a simple "key-value" mode, which greatly increases the scalability of the database

  • Does not follow the SQL standard

  • Does not support ACID (supports transactions but does not support the four major characteristics of transactions <atomicity, isolation, consistency, persistence>)

  • Much better than SQL performance

NOSQL usage scenarios

  1. High concurrent reading and writing of data
  2. Mass data read and write
  3. High scalability for data

NOSQL database

  1. Redis : data is stored in memory, supports persistence, stores data in key-value mode, supports multiple data types, and is generally used as data for cached data to assist persistence

  2. MongoDB : High-performance, open source, document-type database, stored in memory or hard disk, stores data in Key-value mode, value is stored in json format, and provides rich query functions

  3. Hbase : HBase is the database in the Hadoop project. It is mainly used for random and factual read and write scenarios of large amounts of data, and stores data using columnar storage data mode.

1 Introduction to Redis

Redis (Remote Diconary Server) is an open source written in ANSI C language, supports the network, can be memory-based or persistent log type, Key-Value database, and provides multiple language APIs.

Redis itself is an in-memory database that can act as a cache in the application to improve the performance of system data query non-relational database, collectively referred to as: NOSQL.

1.1 Features of Redis

  1. There is no necessary connection between the data
  2. Internal use of single-thread multiple IO multiplexing technology
  3. high performance. (Official test: 50 concurrently execute 100,000 requests, read speed 110,000 times per second, write speed 80,000 times per second)
  4. Multiple data types support;
type of data stored value operations on stored values scenes to be used
string Can be a string, integer or float Operate on the entire string or a part of the string; perform self-increment or self-decrement operations on integers or floating-point numbers; Put common information, strings, pictures or videos and other information in redis, redis is used as the cache layer, and mysql is used as the persistence layer to reduce the read and write pressure of mysql. For example: token
hash An unordered hash table containing key-value pairs Contains methods to add, get, delete a single element Cache : It is intuitive and more space-saving than string to maintain cache information, such as user information, video information, etc.
list A linked list, each node on the linked list contains a string Perform push and pop operations on both ends of the linked list, read single or multiple elements; find or delete elements based on values Message queue, task queue, such as seckill, panic buying, ticket grabbing, etc.
set an unordered collection containing strings A collection of strings, including basic methods to see if there is addition, acquisition, and deletion; it also includes calculation intersection, union, difference, etc. Tag (tag) : Add tags to users, or users add tags to messages, so that those with the same tag or similar tags can recommend things or people to follow.
Likes, dislikes, favorites, etc. , can be put in the set to achieve
z_set Like a hash, it is used to store key-value pairs An ordered mapping between string members and floating-point numbers;
the order of elements is determined by the size of the score; methods include adding, getting, and deleting individual elements, and getting elements based on score ranges or members
Leaderboard : an ordered collection of classic usage scenarios. For example, websites such as novel videos need to rank novel videos uploaded by users. The list can be ranked according to the number of user attention, update time, word count, etc.
  • Note: All Redis data is saved according to key and value, and key is always a string
  1. Persistence support for data disaster recovery

1.2 Redis application scenarios

  1. Accelerated query of hot data, such as hot products, hot news, hot information and other high-visit information
  2. Task queue, such as seckill, snap-up, ticket grabbing, etc.
  3. Instant information query, such as leaderboard, site access statistics, online people statistics, bus arrival information, equipment signals, etc.
  4. Time-sensitive information control, such as time-limited verification codes, time-limited voting, etc.
  5. Distributed data sharing, such as session separation in distributed cluster architecture
  6. message queue
  7. distributed lock

1.3 Redis installation

  1. Download link (Windows version)

https://github.com/microsoftarchive/redis/releases

  1. Download the zip version or installation version (zip version is recommended), decompress
  2. Configure environment variables
  3. Open a cmd window, run redis-serverthe command , and start the redis server

insert image description here

  1. Open another cmd window, run redis-clithe command, and enter the client

insert image description here

  1. Successful installation.

1.4 Thread problems of different versions of Redis

The thread processing methods used in different versions of Redis are different. The following is a brief description of the three versions

  • Previous versions of Redis4 used single-threaded multiplexing IO multiplexing technology, that is to say, versions before Redis 4 used single-threaded

  • Redis4.0 began to support multithreading, but only for delete operations using multithreading , which is introduced in Redis4.0 version

    The lazy deletion (asynchronous deletion) method of the method, the deletion operation is handed over to the background thread for processing, so as to solve the problem of the main thread being stuck

  • The version of Redis6.0 started to really use multithreading for I/O operations, but Redis commands are still executed serially by the main thread.

    Although Redis 6.0 and later versions support multi-threading, it is disabled by default . Developers need to enable and specify in the configuration file

    Determines the number of threads used

    # So for instance if you have a four cores boxes, try to use 2 or 3 I/O
    # threads, if you have a 8 cores, try to use 6 threads. In order to
    # enable I/O threads use the following configuration directive:
    #
    # io-threads 4 设置线程的数量
    #
    # Setting io-threads to 1 will just use the main thread as usual.
    # When I/O threads are enabled, we only use threads for writes, that is
    # to thread the write(2) syscall and transfer the client buffers to the
    # socket. However it is also possible to enable threading of reads and
    # protocol parsing using the following configuration directive, by setting
    # it to yes:
    #
    # io-threads-do-reads no yes为启动多线程
    

2 Redis common commands

Traditional relational databases use tables to store data. Data stored in Redis is stored in a way similar to JavaMap collections. Key-value storage is used. Keys are not allowed to be repeated, but values ​​can be repeated.

  • The data stored in Redis all rely on traditional databases (such as MySQL/Oracle, etc.)
  • The operation of the Redis memory database no longer uses SQL statements, and mainly uses various commands in Redis
specific order Function
select index Switch database (default 15 databases, numbered 0-15)
clear clear screen command
set key value Add a data value corresponding to the data type as string
get key Get value according to key
lpush key value.... Add a data value corresponding to the data type as list
lrange key 0 -1 iterate through the collection
keys pattern
keys *
keys j*
keys *zhong
keys ?ava
keys u[se]r
Get the keys in the current database
Get all the keys in the current database
Get all the keys that start with j
Get all the keys that end in middle
Get a random character in front of the key, and
get the key that ends with ava The first character is u, the second character For, s or e, the key ps whose ending character is r
: "*" matches any character "?" matches a character "[]" matches any of them
exists key Determine whether the key exists
type key Determine the type of key
del key Delete the specified key
fulshdb Clear all data in the library
fulshall Clear all data command
dbsize View the number of keys in the library

expire key 1
pexpire key 1
Set the expiration time of the key
in seconds
and milliseconds
ttl key View the remaining time of expiration (-1 means never expired, -2 means expired)
persist key Set never expires
rename key newkey Modify the name of the key
renamex key newkey Modify the name of the key, if the newkey does not exist, modify it, otherwise the modification fails
sort key
`sort list[asc
desc]<br/>sort list[limit 0 3] [asc
quit exit ESC键 exit command
ping Check the connection with the server command
echo message console print command
move key db Data movement in different libraries
The current library has key data and there is no data with the same name in the No. 1 library
info Or get the current Redis attribute value

3 Redis data types

Redis itself is a Map, in which all data is stored in the form of key: value

key: is a string

value: is data with a specific type

Redis contains 5 basic data types and 3 special types

3.1 string (string String)

String is the most basic data type of Redis. String binary is safe . Redis string can store any data, such as pictures, objects, etc.

  • Single data, one storage space saves one data, if the number stored in it can be used as a number

    redis中最大可以存储512M大小的字符串,如果是数字,取值范围为java总的lang类型取值范围

命令 规则 功能
set key value 如果key存在替换原有value,如果不存在则创建新的数据 存储单个数据
mset key1 value1 key2 value2 ... 同时存储多个数据
get key 获取数据时返回值为nil表示空,没有数据 获取一个数据
mget key1 key2 ... 同时获取多个数据
strlen 获得字符串长度
append key value 如果数据存在追加数据,如果不存在新建数据 向value中增加新数据
getrange key startIndex endIndex startIndex:开始截取,索引从0开始
endIndex:终止截取
截取字符串
setrang key offset value offset:从下标为多少的字符开始替换 字符串某字符替换
setnx key value 如果key存在存值失败,如果不存在则存值 存储一个数据
incr key 如果字符串中存储的是数字则可以进行数值运算,但其数据类型还是string
必须确保值为数字格式,否则会报错,在redis中incr具有原子性.
对key的值自加1,等同于i++
incrby key number 对key的值加上指定的数值(负值进行减法运算),等同于i=i+n
incrbyfloat key number 对key的值加上或减去浮点数
decr key 对key的值自减1,等同于i++
incrby key number 对可以的值减去指定的数值
setex key seconds value 以秒为单位设置存活时间
psetex key millseconds value 以毫秒为单位设置存活时间
set key value [ex seconds][px milliseconds] 使用set方式设置key的存活期,如果使用nx选项则表示setnx+过期时间
set key value [ex seconds][px milliseconds][nx]
incrby key number 对可以的值减去指定的数值
expire key seconds 单独设置过期时间 以秒为单位
set key value [ex seconds][px milliseconds][nx] 以毫秒为单位

存储对象

我们可以使用字符串存储一个对象,但在使用时不方便,所以存储对象一般不使用字符串

string中key的命名规范

redis中常用于存储表中的一条数据(对象),所以key命名规则体现唯一原则:

表名:主键名:主键值:字段名

set user:user_id:1001{username:admin,password}

3.2 hash (哈希HashMap)

hash类型主要用于存储对象,以key field value 的形式存储

hash中的value只能为string不能在value中嵌套hash或list等

insert image description here

  • 常用指令
命令 规则 功能
hset key field value 设置数据 设置单个数据
hmset key field value 同时设置多个数据
hget key 获取数据 获得key对应的整体数据
hget key filed 获得hash单个字段数据
hmget key1 filed1 filed2 ... 同时获取多个数据
hdel key filed 删除数据 删除指定字段
hlen key 获取hash中的字段数量
hexists key filed 存在返回1,不存在返回0 获取hash中是否包含指定字段
hexists key filed 获取hash中的所有字段名和字段值 获取所有字段值
hkeys key 获取所有字段名
hincrby key filed number 设置指定字段数值增加或减少 增加或减少整数(负数为减少)
hincrbyfloat key filed number 增加或减少浮点数(负数为减少)

3.3 list (列表LinkedList)

在Redis中可以把list用作栈、队列、阻塞队列

list中允许存放重复数据

list中存储的数据有序(指进入顺序<分左右>)

  • 常用指令

    ① 向列表添加数据

    • 左边开始添加:lpush key value
    • 右边开始添加:rpush key value

    ② 从list中获取元素

    • 根据起始和结束下标获取此范围内的列表元素:lrange key startIndex endIndex

    ③ 从list中弹出元素

    • 获得列表头部的第一个元素并从列表中移除:lpop key
    • 获得列表尾部的第一个元素并从列表中移除:rpop key

    ④ 通过下标获取list中的某个元素

    lindex key index

    ⑤ 获得列表中元素的数量(长度)

    llen key

    ⑥ 根据元素值从列表中移除指定数量的元素

    lrem key count value

    ⑦ 截取子list(截断子元素)

    • 截断后list中剩余的数据为截断数据 :ltrim key start stop

    ⑧ 将原列表中最后一个元素移到新列表中

    source:列表

    destination:新列表

    rpoplpush source destination

    ⑨ 根据下标重置list中的一个元素(根据下标修改list中的一个元素)

    lset key index value

    ⑩ 向某个元素前或后插入一个元素

    linsert key BEFORE|AFTER pivot value

3.4 set (集合HashSet)

不保证顺序,集合不能存放重复元素

  • 常用指令

    ① 向set集合中添加一个元素

    sadd key value1 value2...

    ② 查看set集合中所有元素

    smembers key

    ③判断一个元素是否存在于set集合中

    0表示不存在 1表示存在

    sismembers key value

    ④获取set集合元素个数

    scard key

    ⑤ 移除一个元素

    srem key value

    ⑥ 随机抽取一个元素

    • 随机抽取一个或者多个元素:srandmember key [count]

    ⑦ 随机删除元素

    • 随机删除一个或者多个元素:spop key [count]

    ⑧将一个特定的值,移动到另一个set集合中

    destination:另外一个集合

    smove source destination member

    ⑨ 集合操作

    • 差集:sdiff key [key ...]
    • 交集:sinter key [key...]
    • 并集:sunion key [key..]

3.5 sorted_set又称z_set(有序集合TreeSet)

该集合是对set集合的改造,在set集合中加入了一个字段值,用于存储排序规则数据,该数据只负责排序不起其他作用

  • zset存储结构

insert image description here

  • 常用指令

    ① 向z_set集合中添加元素

    zadd key score1 value1 score2 value2...

    ② 获取z_set集合中的元素

    • 从小到大的顺序显示元素信息,withscores显示排序规则字段:zrange key start stop [WITHSCORES]
    • 从大到小的顺序显示元素信息,withscores显示排序规则字段:zrevrangekey start end [WITHSCORES]

    ③ 按条件获取z_set中的元素

    • 获取min-max之间的元素可用limit限制:zrevrangebyscore key min max [limit] [withscores]
    • 降序:zrevrangebyscore key max min [limit] [withscores]

    ④ 增加或减少z_set中元素score

    • zincrby key increment value

    ⑤ 删除z_set中的元素

    • 根据元素名删除一个或多个元素 :zrem key member1 member2...
    • 删除指定下标范围的元素:zremrangebyrank key start stop
    • 根据socres指定范围删除元素 :zremrangebyscore key min max

    ⑥ 获得元素在集合中的排名

    • 升序排名:zrank key member
    • 降序排名:zrevrank key member

    ⑦ 获得集合中元素数量

    • 获得集合中元素数量:zcard key
    • 获得指定范围的元素数量:zcard key min max

    ⑧ 集合交集和并集

    • 集合交集操作,将多个集合的交集存 入到newset集合中,相交集合的数量个setcount指定的数量要一致,默认对交集数据进行求和运算, 也可以获得最大值或最小值等运算

      zinterstore newset setcount set1 set2 ...

    • 集合并集操作:zunionstore newset setcount set1 set2 ...

3.6 特殊类型

1.geospatial :地理位置

城市经纬度查询: 经纬度查询

  • 两极无法直接添加,我们一般会下载城市数据,直接通过java程序一次性导入!
  • 有效的经度从-180度到180度。
  • 有效的纬度从-85.05112878度到85.05112878度。
  • m 为米。km 为千米。mi 为英里。ft 为英尺。

2.hyperloglog : 基数

数学层面上可以说是:两个数据集中不重复的元素
但是再Redis中,可能会有一定的误差性。 官方给出的误差率是0.81%。
Hyperloglog的优点: 占用的内存是固定的,2^64个元素,相当于只需要12kb的内存即可。效率极高!

3.bitmap 位图

都是操作二进制位来进行记录,只有0 和 1 两个状态

4 Jedis

4.1 Jedis简介

jedis是Java操作redis的一个工具,等同于jdbc,可用使用jedis实现java操作redis的目的。

Spring中操作Redis的技术是Spring Data Redis

4.2 Jedis操作Redis

  1. 引入Jedis的依赖包
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
	<version>4.3.1</version>
</dependency>
  1. 连接Redis
		/**
         * 创建jedis对象并指定服务器ip地址及端口号
         * 参数1:Redis服务器地址
		 * 参数2:Redis服务器端口号
         */
        Jedis jedis=new Jedis("127.0.0.1",6379);
  1. 操作Redis
        jedis.set("num1","0");
        String value = jedis.get("num1");//根据key获得对应的value
  1. 关闭连接
//关闭连接
jedis.close();
  • Jedis操作Sting

    1. 向redis添加数据

      //添加一条数据
      jedis.set("num1","0");
      //添加多条数据
      jedis.mset("num3","2","num4","3");
      
    2. 获得redis中元素

      ①根据key获得对应的value

           //获取一个数据
               String value = jedis.get("num1");
           System.out.println(value);
           //获取多个数据
           List<String> mget = jedis.mget("num1", "num2", "num3");
              System.out.println(mget);
      

      ②获取redis所有元素的key

           //获取redis所有元素的key
              Set<String> keys = jedis.keys("*");
              System.out.println(keys);
      
    3. 设置时效

      jedis.expire("num1",1000);
      //获得剩余时效
      long num11 = jedis.ttl("num1");
      System.out.println(num11);
      
  • Jedis操作List

        public static void jedisForList(){
          
          
            /**
             * 创建jedis对象并指定服务器ip地址及端口号
             */
            Jedis jedis = new Jedis("127.0.0.1", 6379);
            //向Redis中添加list数据
            jedis.lpush("list","a","b","c");
            jedis.rpush("list","x");
            //从Redis中将key为list1的数据获取,返回java.util.List集合
            List<String> list1 = jedis.lrange("list1", 0, -1);
            //遍历List集合
            for(String str : list1){
          
          
                System.out.println(str);
            }
            //关闭Redis的连接
            jedis.close();
        }
    
  • Jedis操作set集合数据

    	    public static void jedisForSet(){
          
          
            /**
             * 创建jedis对象并指定服务器ip地址及端口号
             */
            Jedis jedis = new Jedis("127.0.0.1", 6379);
            //向Redis中添加set集合数据
            jedis.sadd("set1","v1","v2","v3");
            //从Redis中获取key为set1的数据,返回值自动封装到java.util.Set集合中
            Set<String> set1 = jedis.smembers("set1");
            for(String set : set1){
          
          
                System.out.println(set);
            }
            //关闭与Redis的连接
            jedis.close();
        	}
    
  • Jedis操作Map

        public static void jedisForMap(){
          
          
            /**
             * 创建jedis对象并指定服务器ip地址及端口号
             */
            Jedis jedis = new Jedis("127.0.0.1", 6379);
            //向hash中添加数据
            Map valMap = new HashMap<String,Object>();
            valMap.put("id","001");
            valMap.put("name","小明");
            valMap.put("age","20");
            /**
             * 参数1:key
             * 参数2:value对应的是map集合
             */
            jedis.hmset("user",valMap);
            Map<String,String> user = jedis.hgetAll("user");
            System.out.println(user);
            //关闭与Redis的连接
            jedis.close();
        }
    

5 Redis基本配置

  • redis启动时会读取相应配置文件,我们可以通过修改redis的配置文件对redis进行配置,同时也

    可以设置多个不同的配置文件,启动多个redis服务,如redis-6379.conf,redis-6380.conf

    ① Redis服务端启动方式

    • 默认启动方式: redis-server 读取的配置文件为默认的件redis.windows-service.conf

    • 指定配置文件启动方式:redis-server (xxx/redis-6380.conf)

      在redis目录里: redis-server redis-6380.conf

      配置文件在指定文件夹里(此处为redis目录下的config文件夹):redis-server config/redis-6381.conf

    ② Redis客户端启动方式

    • 默认启动方式:redis-cli访问默认服务器
    • 访问指定端口的服务:redis-cli -p 6380
    • 访问指定服务器上特定端口的redis服务:redis-cli -h 127.0.0.1 -p 6381

    基本配置

    #服务器绑定的ip地址
    bind 127.0.0.1
    
    #Redis服务器绑定的服务器端口号
    port 6380
    
    #超时时间  0表示不超时
    timeout 0
    
    # redis是否使用守护线程,设置为no表示不使用启动时会在控制台上打印启动信息
    # 设置为yes表示使用守护线程,后台启动,不打印启动信息(该配置在windows上不支持)
    # daemonize no
    
    #日志文件,该文件配置后,redis相关的日志信息会输出到指定的配置文件中,便于查看
    logfile "E:/Redis/Redis-x64-3.2.100/config/log/redis-6380.log"
    
    #Redis服务器数据库的数量
    databases 16
    
    # 指定存储到本地的数据库文件时是否对数据进行压缩,默认为yes,采用LZF压缩(一般开启)
    rdbcompression yes
    
    # 设置是否对rdb文件格式进行校验,该校验在写文件和读文件时均会进行,默认为yes(一般开启,如
    果设置为no读写性能会提升但存在数据损坏风险)
    rdbchecksum yes
    
    # 当后台保存数据时如果出现错误是否停止保存操作
    stop-writes-on-bgsave-error yes
    

6 Redis持久化

  • redis是基于内存的数据库,它是存储在内存上,如果突然断电或遇到其他意外情况把内存中的数

    据清除,就会造成redis中数据的丢失,为避免这样的情况出现而操作损失,在redis中提供了持久

    化机制。

  • redis持久化指将redis中的数据保存到可以永久存储的存储介质中,在需要时将保存的数据进行恢复。

Redis中提供了两种持久化方案:

(1) RDB方式(快照方式):将当前数据状态以快照的形式进行保存,存储格式简单,关注点在数据

(2) AOF方式(日志方式):将操作数据的过程以日志的方式记录下来,存储格式复杂,关注点在操作

数据的过程。

7.1 RDB实现持久化

RDB方式实现持久化,使用save命令可以将当前的redis中的数据存储到磁盘上,存储文件的默认名称为dump.rdb

  • 当redis服务启动时,会自动读取rdb文件,将已存储的备份进行恢复

  • save指令是指示redis立即将数据存储到磁盘上进行备份,但如果存储的数据量过大,而且同时又

    有其他客户端也要访问redis时就会造成堵塞状态,影响性能(不建议使用),redis提供了后台执行命

    bgsave来解决这个问题

  • savebgsave两个命令都会调用 rdbSave 函数将当前Redis中的数据存入到rdb文件中,但两者调

    用的方式不同

    • save直接调用rdbSave,会阻塞Redis主进程,直到保存完成为止。在主进程阻塞期间,服务器不能处 理客户端的任何请求。
    • bgsave则调用fork函数生成一个子进程,子进程负责调用rdbSave,并在保存完成之后向主进程发送 信号,通知保存已完成。Redis服务器在bgsave执行期间仍然可以继续处理客户端的请求。
  • 在配置文件里配置rdb的路径和文件名

    #指定持久化文件存储路径
    dir E:/Redis/Redis-x64-3.2.100/config/data

    #指定持久化文件文件名
    dbfilename dump-6380.rdb

ps:为什么在配置文件里持久化文件名不在dir(持久化文件存储路径)里配置?

答:因为持久化方式不止一种

  • 手动保存过于繁琐,Redis里面提供了一种"自动保存快照"的方式,当达到存储Redis要求时,Redis就会自动调用bgsave指令,自动保存当前数据,我们需要在配置文件里配置自动保存的时间及数据变化量(不配置不会自动保存)
    #该配置表示开启Redis的自动备份功能
    #配置rdb快照方式自动保存时间及数据变化量
    #每隔900s内有一个数据发送改变则自动保存
    save 900 1 
    #每隔300s内有10个数据发送改变则自动保存
    save 300 10
    #每隔60s内有10000个数据发送改变则自动保存
    save 60 10000

PS:

  • 根据使用场景进行设置,频率过高和过低都会使性能受到影响

  • 调用debug reload 指令重启服务器时会自动保存数据

  • 服务器关闭时(shutdown指令)会自动保存数据

  • RDB持久化方式的优点

    RDB是一个紧凑压缩的二进制文件,存储效率高

    RDB内部存储的是Redis在某个时间点的数据快照,非常适用于数据备份,数据整体复制等场景

    RDB恢复数据的速度要比AOF快

  • RDB持久化方式的缺点

    RDB方式基于快照思想,每次读写全部数据,当数据量巨大时效率低、IO读写性能低下

    RDB方式无法实时备份数据,数据丢失的可能性大

    bgsave指令每次执行要创建子进程,内存会产生额外的消耗

7.2 AOF实现持久化

  • AOF持久化是以独立日志方式记录每次写命令,重启时在重新执行AOF文件中的命令以恢复数据

  • 与RDB相比AOF不是存储所有数据而是存储操作数据的过程,实时性更高

  • AOF解决了数据持久化的持久性,目前AOF已经是数据持久化的主流方式

  • AOF持久化方式写数据的过程:

    • Redis将写命令写入AOF写缓冲区
    • 达到一定程度,将AOF缓冲区中数据一次性写入AOF文件中
  • AOF写数据的三种策略:

    • always(每次写都存入)

      每次写都存入,虽然保证了数据存储的实时性,准确性,但是当写入数据过多,每次写入都需要IO操作,就会产生大量IO操作,效率低下(不建议使用)

    • everysec(每秒写入)

      每秒将缓冲区中的写操作同步到AOF文件中,数据实时性,准确性,性能较高(建议使用,Redis默认使用方式)

    • no(系统写入)

      由操作系统控制每次同步到AOF的周期

  • AOF持久化的使用

    • AOF默认在Redis中是禁用的,需要在配置文件中打开,设置为yes,开启后服务器会自动生产一个aof文件,用于备份数据

      #配置是否使用AOF存储数据,默认为no
      appendonly no|yes
      
    • 在配置文件里指定aof文件名

      #配置aof文件名
      appendfilename "appendonly-6380.aof"
      
    • 在配置文件中配置AOF存储所使用的策略,默认为everysec策略

      # 配置AOF存储的写入策略
      # appendfsync always
      appendfsync everysec
      # appendfsync no
      
  • AOF重写

    随着不断向aof写入数据,aof文件会越来越大,且操作中会有大量重复且无效的操作,替换过程,Redis引入了AOF重写机制,将对AOF压缩,将AOF中原有指令进行重组,将无效,多余的指令移除,多条追加指令进行合并,转换为最终数据对应的指令进行记录。以实现压缩aof文件的目的

    • AOF重写的作用

      ① 降低磁盘占用量,提高磁盘使用率

      ② 提高持久化效率,降低持久化时间,提高IO性能

      ③ 提高数据恢复效率

    • AOF重写规则

      ① 超时数据不再写入文件

      ② 忽略无效指令,重写时使用进程内的数据直接生成,这样新的aof文件只保存最终数据的写入命令

      ③ 对同一数据的多条命令进行合并

      • 如:lpush list a,lpush list b,lpush list c转换为l push a,b,c
    • AOF重写的使用

      ① 使用bgrewriteaof手动重写

      127.0.0.1:6380> set name xiaowang
      OK
      127.0.0.1:6380> set age 20
      OK
      127.0.0.1:6380> set sex 1
      OK
      127.0.0.1:6380> set num01 10
      OK
      127.0.0.1:6380> set num02 10
      OK
      127.0.0.1:6380> delete num01
      (error) ERR unknown command 'delete'
      127.0.0.1:6380> del num01
      (integer) 1
      127.0.0.1:6380> set num02 20
      OK
      #查看aof文件
      127.0.0.1:6380> bgrewriteaof
      Background append only file rewriting started
      127.0.0.1:6380>
      #查看重写的aof文件
      

      ② 在配置文件里进行配置实现自动重写

      Redis中配置好AOF自动重写的触发条件后,当条件满足自动触发,在Redis中有两个触发条件配置,当达到两个条件就会自动触发AOF重写

      # AOF自动触发百分比
      auto-aof-rewrite-percentage 100
      # AOF自动触发最小尺寸
      auto-aof-rewrite-min-size 64mb
      

      当Reids中自动触发条件大于触发参考值时,执行AOF重写(参考条件可根据info指令查看,Redis中已配置好)

      # AOF自动触发参考值
      aof_current_size:60 #当AOF触发条件的最小尺寸大于该值自动执行AOF重写
      aof_base_size:60 #AOF触发基础尺寸
      # 当前使用百分比大于或等于自动触发百分比时会自动执行AOF重写
      # 公式:aof_current_size-auto-aof-rewrite-min-size/aof_base_size>=autoaof-rewrite-percentage
      

7 Redis中的事务

传统的事务:事务对应一个sql集,其中包含sql语句,这些sql语句要么全部执行,要么不执行,必须符合事务的(ACID)特性

Redis中的事务:不需要符合所谓(ACID)四大特性。

  • Redis中事务是为了保证多条执行的指令在执行过程中不被打断
  • 开启事务:multi指令,该指令用于设置事务的开始位置,该指令后的所有指令都会加入Redis的事务中,形成一个指令队列

  • 执行事务:exec指令,该指令用于执行事务,表示事务的结束和指令队列的执行,与multi成对使用

    insert image description here

  • 取消事务:discard指令,该指令必须在multi之后,在exec之前,该指令用于取消当前事务

PS:

Redis事务中如果出现指令语法错误,则会自动取消当前事务

在事务执行过程中,即使出现错误,事务也会继续执行

8 Redis中锁的概念

  • watch监控锁

    当同一个数据需要改变时,可能会出现多个人同时修改该数据,数据可能发生错乱,为了避免发生数据修改错乱,此时加入watch锁,只允许数据修改一次数据,当一个人修改后其他人则不能改变,其他人修改该数据,则终止事务的执行

    • 加入watch锁,执行事务前,如果数据发生变化,则终止事务执行

      watch key[key1 key2....]

    • 关闭watch锁

      unwatch

  • 分布式锁

    当多个线程同时操作一个数据数,可能出现数据错乱,为避免该情况,我们需要将该数据锁起来,当一个线程操作完成,才允许另外一个线程操作该数据,Redis使用分布式锁实现此场景

    Redis中没有分布式锁,我们可以使用setnx设计一个分布式锁

    • 添加一个key,该key为分布式锁,我们知道setnx在设置数据时如果数据存在则返回0

    • 设置该数据为锁,其他客户端要操作数据前先通过该指令的返回值检测如果返回值为0
      则表示当前数据已被锁定不能操作,如果返回值为1表示加锁,然后操作。

      setnx lock-num 1

    • 对加锁的数据使用后要解锁,通过del lock-num移除数据的方式实现解锁过程
      del lock-num

  • 死锁

    通过分布式锁的机制可以实现对数据操作的排他性,但数据使用结束后需要解锁(谁加锁,谁解锁),但有时可能会忘记解锁或发送意外无法解锁,就成了死锁。。。

    设计分布式锁时不允许出现死锁

    在设置分布式锁就需要添加时效,在一定时间后自动解锁

    set key value [ex seconds][px milliseconds][nx]:设置分布式锁

9 Springboot整合Redis

Spring使用Spring Data与Redis进行整合,在SpringData中提供了一个模板类RedisTemplate来实现redis的相关操作

9.1 添加相关依赖和设置配置

  • 添加相关依赖

    • 引入springBoot父项目
       <!--引入springBoot父项目
           springboot对spring相关版本进行规定
    	   也对spring基础配置进行了约定
         -->
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.7.9</version>
        </parent>
    
    • 引入spring-boot-start-web
    <!-- spring-boot-starter-web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-web</artifactId>
        <version>2.7.9</version>
    </dependency>
    
    • 引入spring-boot-start-data-redis
    <!-- spring-boot-starter-data-redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
        <version>2.7.9</version>
    </dependency>
    
  • 设置配置

    server.context:
      port: 80
    
    
    spring:
      redis:
        host : 127.0.0.1 #配置ip地址
        port : 6380 #配置端口号
        jedis:
          #配置连接池
          pool:
            max-active: 10 # 最大活动连接
            min-idle: 2 # 最小空闲连接
            max-idle: 5 # 最大空闲连接
            max-wait: 1000 # 最大等待时间
    
  • 创建Bean

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
          
          
       private Integer userId;
       private String username;
       private String password;
    }
    

9.2 SpringDataRedis对象的序列化

要将程序中的数据进行外部存储,都必须将数据进行序列化。

Data is stored from the outside to the program, and the data also needs to be deserialized

  • SpringDataRedis uses the JDK method to serialize the data in the program by default, requiring the class to implement the serialization interface

    In this method, there will be surplus data in redis, so we use the following method to set serialization

    private RedisTemplate redisTemplate;
    @Autowired
    public ApplicationTest(RedisTemplate redisTemplate) {
          
          
        this.redisTemplate = redisTemplate;
          /**
           * 设置redisTemplate中key和value的序列化
           * SpringDateRedis默认使用JDKSerializationRedisSerializer对key和value进行序列化
           * GenericJackson2JsonRedisSerializer:将任意类型的数据转化为json串进行序列化到redis中
           * Jackson2JsonRedisSerializer<User>(User.class):将指定类型转化json并序列化到redis中
           * GenericToStringSerializer<User>(User.class):将任意类型数据转化为字符串
           */
    //设置key序列化
    //StringRedisSerializer:只支持字符串
    redisTemplate.setKeySerializer(new StringRedisSerializer());
    //设置value序列化
    redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    //redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<User>(User.class));
    //redisTemplate.setValueSerializer(new GenericToStringSerializer<User>(User.class));
    }
    

9.3 SpringBoot integrates Redis

  • operation string

        @Test
        void operateString() {
          
          
            //获得字符串操作对象
            ValueOperations valueOperations = redisTemplate.opsForValue();
    //        valueOperations.set("user",new User());//添加对象
    //        valueOperations.set("num",100);
    //        Integer num = (Integer) valueOperations.get("num");
    //        Long num = valueOperations.increment("num");//incr命令
    //        Long num = valueOperations.increment("num", 10);//incrby命令
    //        User user = (User) valueOperations.get("user");
    //        valueOperations.set("username","admin",100, TimeUnit.SECONDS);//添加字符串并设置过期时间
    //        valueOperations.set("age",18, Duration.ofSeconds(10));
    //        Map<String,Object> map=new HashMap<>();
    //        map.put("username","admin");
    //        map.put("age",88);
    //        valueOperations.multiSet(map);//mset命令
    //        ArrayList arrayList=new ArrayList();
    //        Collections.addAll(arrayList,"username","age");
    //        List list = valueOperations.multiGet(arrayList);//mget命令
    //         valueOperations.setIfAbsent("age",18);//setnx命令
    //        valueOperations.setIfAbsent("age1",18);
    //        System.out.println(user);
        }
    
  • operation list

        @Test
        void operateList() {
          
          
            ListOperations listOperations = redisTemplate.opsForList();
    //        listOperations.leftPush("list","aaa");//lpush
    //        listOperations.leftPush("list","bbb");//lpush
    //        listOperations.rightPush("list","ccc");//rpush
    
    //        listOperations.leftPushAll("list","ddd","eee","fff");
    //        listOperations.leftPop("list");//lpop
    //         List list = listOperations.range("list", 0, -1); //lrange key start end
    //        list.forEach(System.out::println );
            
        }
    
  • operation hash

        @Test
        void operateHash() {
          
          
            HashOperations hashOperations = redisTemplate.opsForHash();
    //        hashOperations.put("hash","hashKey","value");//hset
            Map<String,Object> map=new HashMap<>();
            map.put("hashKey01","value01");
            map.put("hashKey02","value02");
            map.put("hashKey03","value03");
            map.put("hashKey04","value04");
            hashOperations.putAll("hash",map);//hmset
    //        System.out.println(hashOperations.get("hash", "hashKey"));//hget
            System.out.println(hashOperations.entries("hash"));//hmget
        }
    
  • operation set

        @Test
        void operateSet() {
          
          
            SetOperations setOperations = redisTemplate.opsForSet();
    //        setOperations.add("key1","value1","value2","value1");//sadd
    
    //        System.out.println(setOperations.isMember("key1", "value"));//sismenmbers
            setOperations.add("key1",new User());
            System.out.println(setOperations.members("key1"));//smembers
        }
    
  • Operation Z_set

        @Test
        void operateZSet() {
          
          
            ZSetOperations zSetOperations = redisTemplate.opsForZSet();
    //        zSetOperations.add("scores","小明",90.9);//zadd
    //        zSetOperations.add("scores","花花",88.6);
    //        Set scores = zSetOperations.range("scores", 0, -1);//zrange
    //        Set <ZSetOperations.TypedTuple> scoreSet=new HashSet<>();
    //        scoreSet.add(ZSetOperations.TypedTuple.of("张三",100d));
    //        scoreSet.add(ZSetOperations.TypedTuple.of("李四",60.55));
    //        zSetOperations.add("scores",scoreSet);
            /**
             * 根据z_set的key获得value和filed,filed和value被封装在TypedTuple中
             */
    //        Set<ZSetOperations.TypedTuple> scores = zSetOperations.reverseRange("scores", 0, -1);//zrevrange
    //        scores.forEach(System.out::println);
    //        for (ZSetOperations.TypedTuple typedTuple : scores) {
          
          
    //            System.out.println(typedTuple.getScore() + ":" + typedTuple.getValue());
    //        }
    
            //获得前三名
    //        Set<ZSetOperations.TypedTuple> scores = zSetOperations.reverseRangeByScoreWithScores("scores", 0, 100, 0, 3);
    //        for (ZSetOperations.TypedTuple typedTuple:scores){
          
          
    //            System.out.println(typedTuple.getScore()+":"+typedTuple.getValue());
    //        }
    //        Long rank = zSetOperations.rank("scores", "小明");//获得该值得排名
    //        System.out.println(rank+1);
            Long scores = zSetOperations.zCard("scores");//获得元素数量
            System.out.println(scores);
        }
    

  • Learning comes from Xi'an Jiazhong training

Guess you like

Origin blog.csdn.net/woschengxuyuan/article/details/126994785