An introductory learning tutorial for Redis suitable for beginners with zero foundation, teaching you Redis installation, data types and transactions step by step!

1. Introduction to Redis

1.1 What is Redis

Redis (Remote Dictionary Server), that is, remote dictionary service, 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 APIs in multiple languages. Redis will periodically write updated data to disk or write modification operations to additional record files, and on this basis, master-slave (master-slave) synchronization is realized. Redis is a high-performance key-value database. The emergence of redis largely compensates for the lack of key/value storage such as memcached, and can play a very good supplementary role in relational databases in some occasions. It provides Java, C/C++, C#, PHP, JavaScript, Perl, Object-C, Python, Ruby, Erlang and other clients, which are very convenient to use.

1.2 What Redis can do

  1. Memory storage, persistence, memory is lost when power is off, so persistence is very important (rdb, aof)
  2. High efficiency, can be used for cache
  3. publish subscribe system
  4. Map information analysis
  5. timer, counter

1.3 Features of Redis

  1. various data types
  2. persistent storage
  3. cluster
  4. thing

2. Installation and use of Redis

2.1 Install Redis under windows (not recommended)

insert image description here

1. Double-click redis-server.exe , if it crashes, open the command in this directory, enter redis-server.exe redis.windows.conf and press Enter, as shown in the figure below:

insert image description here

2. After success, double-click redis-cli.exe .

2.2 Install Redis under virtual machine Linux (recommended)

1. Download the installation package and decompress it

# 切换到root目录下

[root@wyc ~]# cd /root

# 在root目录下下载redis的安装包

[root@wyc ~]# wget http://download.redis.io/releases/redis-7.0.5.tar.gz

--2022-10-22 13:30:24-- http://download.redis.io/releases/redis-7.0.5.tar.gz

正在解析主机 download.redis.io (download.redis.io)... 45.60.125.1

正在连接 download.redis.io (download.redis.io)|45.60.125.1|:80... 已连接。

已发出 HTTP 请求,正在等待回应... 200 OK

长度:2968205 (2.8M) [application/octet-stream]

正在保存至: “redis-7.0.5.tar.gz”

100%[=============================================>] 2,968,205  862KB/s 用时 3.4s  

2022-10-22 13:30:28 (862 KB/s) - 已保存 “redis-7.0.5.tar.gz” [2968205/2968205])

[root@wyc ~]# ls

anaconda-ks.cfg    **redis-7.0.5.tar.gz** 模板 图片 下载 桌面

initial-setup-ks.cfg 公共        视频 文档 音乐

# 切换到opt目录下

[root@wyc ~]# cd /opt

[root@wyc opt]# ls

rh

[root@wyc opt]# cd /root

# 将redis安装包移动到opt目录下

[root@wyc ~]# mv redis-7.0.5.tar.gz /opt

[root@wyc ~]# ls

anaconda-ks.cfg initial-setup-ks.cfg 公共 模板 视频 图片 文档 下载 音乐 桌面

[root@wyc ~]# cd /opt

[root@wyc opt]# ls

**redis-7.0.5.tar.gz** rh

# 解压redis安装包

[root@wyc opt]# tar -zxvf redis-7.0.5.tar.gz

[root@wyc opt]# ls

redis-7.0.5 redis-7.0.5.tar.gz rh

2. Enter the decompressed file, you can see the redis configuration file

insert image description here

3. Basic environment installation

The commands used here are:

  • yum install gcc-c++
  • gcc -v
  • make
  • make install
[root@wyc redis-7.0.5]# gcc -v

使用内建 specs。

COLLECT_GCC=gcc

COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper

目标:x86_64-redhat-linux

配置为:../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux

线程模型:posix

gcc 版本 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)

[root@wyc redis-7.0.5]# yum install gcc-c++

已加载插件:fastestmirror, langpacks

Loading mirror speeds from cached hostfile

* base: [mirrors.ustc.edu.cn](http://mirrors.ustc.edu.cn/)

* extras: [mirrors.ustc.edu.cn](http://mirrors.ustc.edu.cn/)

* updates: [mirrors.ustc.edu.cn](http://mirrors.ustc.edu.cn/)

base                              | 3.6 kB 00:00:00   

extras                             | 2.9 kB 00:00:00   

updates                             | 2.9 kB 00:00:00   

软件包 gcc-c++-4.8.5-44.el7.x86_64 已安装并且是最新版本

无须任何处理

[root@wyc redis-7.0.5]# make

...

[root@wyc redis-7.0.5]# make install

4. The default installation path of redis is usr/local/bin

insert image description here

5. Copy the redis configuration file to our current directory

insert image description here

6. Redis is not started in the background by default, and the configuration file needs to be modified

The commands used here are: vim redis.conf

Change daemonize's no to yes

insert image description here

7. Start the redis service and use redis-cli for connection testing

The commands used here are:

  • redis-server RedisConfig/redis.conf
  • redis-cli -p 6379

insert image description here

8. Check whether the redis process is enabled

insert image description here

9. How to close the redis service?

insert image description here

10. Check whether the process exists again (open another terminal)

The commands used here are: ps -ef|grep redis

insert image description here

2.3 Check the IP address of CentOS

Enter ip to query and name ip addr , and the following situation will appear: The ip address of centos is the inet value in the ens33 entry

[root@wyc ~]# ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000

  link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

  inet 127.0.0.1/8 scope host lo

    valid_lft forever preferred_lft forever

  inet6 ::1/128 scope host

    valid_lft forever preferred_lft forever

2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000

  link/ether 00:0c:29:70:f6:f4 brd ff:ff:ff:ff:ff:ff

  inet 192.168.239.128/24 brd 192.168.239.255 scope global noprefixroute dynamic ens33

    valid_lft 1666sec preferred_lft 1666sec

  inet6 fe80::29ae:bc:3ee5:cc9f/64 scope link noprefixroute

    valid_lft forever preferred_lft forever

3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000

  link/ether 52:54:00:d0:ea:2f brd ff:ff:ff:ff:ff:ff

  inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0

    valid_lft forever preferred_lft forever

4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN group default qlen 1000

  link/ether 52:54:00:d0:ea:2f brd ff:ff:ff:ff:ff:ff

2.4 Performance test

redis-benchmark is a stress testing tool, the official performance testing tool

insert image description here

simple test

# 100个并发连接 1000个请求

redis-benchmark -h localhost -p 6379 -c 100 -n 1000

insert image description here

How can I view these analytics?

insert image description here

3. Basic knowledge of Redis

3.1 Simple operation of Redis

Redis has 16 databases by default

insert image description here

The default is the 0th one, you can use select to switch databases

[root@wyc bin]# redis-server RedisConfig/redis.conf

[root@wyc bin]# redis-cli -p 6379

127.0.0.1:6379> ping

PONG

# 切换第四个数据库

127.0.0.1:6379> select 3

OK

# 查看数据库大小

127.0.0.1:6379[3]> dbsize

(integer) 0

127.0.0.1:6379[3]> set age 20

OK

127.0.0.1:6379[3]> dbsize

(integer) 1

127.0.0.1:6379[3]> get age

"20"

127.0.0.1:6379[3]> key *

(error) ERR unknown command 'key', with args beginning with: '*'

127.0.0.1:6379[3]> keys *

1) "age"

Clear the current database content flushdb

127.0.0.1:6379[3]> keys *

1) "age"

127.0.0.1:6379[3]> flushdb

OK

127.0.0.1:6379[3]> keys *

(empty array)

Clear all database contents flushall

127.0.0.1:6379> keys *

1) "mylist"

2) "key:__rand_int__"

3) "counter:__rand_int__"

4) "myhash"

5) "name"

127.0.0.1:6379> select 3

OK

127.0.0.1:6379[3]> set age 20

OK

127.0.0.1:6379[3]> keys *

1) "age"

127.0.0.1:6379[3]> flushall

OK

127.0.0.1:6379[3]> keys *

(empty array)

127.0.0.1:6379[3]> select 0

OK

127.0.0.1:6379> keys *

(empty array)

3.2 Redis is single-threaded

The official stated that Redis is based on memory operations, and the CPU is not the performance bottleneck of Redis. The bottleneck of Redis is based on the memory and network bandwidth of the machine. Since it can be implemented with a single thread, it uses a single thread. Redis is written in C language, and the official data is 100,000+ QPS, which is no worse than Memecache, which also uses key-value.

Why is Redis single-threaded so fast?

Myth 1: A high-performance server must be multi-threaded?

Myth 2: Multithreading (CPU context switching) must be more efficient than single threading?

Core : Redis puts all the data in memory, so it is the most efficient to use a single thread to operate. Multi-threading (CPU context switching: time-consuming operation) will bring more in design and implementation. of complexity. For memory systems, the efficiency is the highest if there is no context switching. Using a single thread can save the time of CPU context switching when multi-threading is used. There is no need to consider the problem of locks. There are no operations such as locking and releasing locks. There is no performance consumption caused by deadlock problems. In the case of memory, single-threading is the best. plan.

3.3 Some common commands of Redis

keys * # 查看所有的key

flushdb # 清空当前数据库,

flushall # 清空所有数据库

exists key # 判断值是否存在

move name 1 # 移动key为name到数据库1

expire name 10 # 设置key为name的值10s后过期

ttl name # 查看当前key剩余秒数

type name # 查看当前key为name的值类型

append key abc # 追加abc到key的末尾

strlen key # 查看key的长度

If you encounter commands that you don’t know later, you can view the help documentation on the official website

Go to Redis Command Center

3.4 Five major data types of Redis

Check out the official documentation

Redis is an open source (BSD licensed), in-memory data structure storage system that can be used as a database, cache, and messaging middleware. It supports many types of data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs and geospatial ( geospatial) index radius query. Redis has built-in replication, LUA scripting (Lua scripting), LRU-driven events (LRU eviction) transactions (transactions) and different levels of disk persistence (persistence), and provides High availability (high availability).

3.4.1 String (string)

# strlen 获取字符串的长度

# exists 判断key是否存在

127.0.0.1:6379> set name zhangsan # 设置值

OK

127.0.0.1:6379> keys * # 获得所有的key

1) "name"

127.0.0.1:6379> get name # 获得值

"zhangsan"

127.0.0.1:6379> append name Hello # 追加字符串,如果当前key不存在,就相当于set key

(integer) 13

127.0.0.1:6379> get name

"zhangsanHello"

127.0.0.1:6379> append age 18 # 此时相当于set age 18

(integer) 2

127.0.0.1:6379> get age

"18"

127.0.0.1:6379> strlen name # 获取字符串的长度

(integer) 13

127.0.0.1:6379> exists name # 判断key是否存在

(integer) 1

######################################################################

# incr decr incrby decrby 步长

127.0.0.1:6379> set views 0

OK

127.0.0.1:6379> get views

"0"

127.0.0.1:6379> incr views # 自增1,浏览量+1

(integer) 1

127.0.0.1:6379> get views

"1"

127.0.0.1:6379> incr views # 自增1,浏览量+1

(integer) 2

127.0.0.1:6379> get views

"2"

127.0.0.1:6379> decr views # 自减1,浏览量-1

(integer) 1

127.0.0.1:6379> get views

"1"

127.0.0.1:6379> incrby views 10 # 设置步长,指定增加量为10

(integer) 11

127.0.0.1:6379> get views

"11"

127.0.0.1:6379> decrby views 20 # 设置步长,指定减少量为20

(integer) -9

127.0.0.1:6379> get views

"-9"

######################################################################

# getrange 获取指定范围的字符串

127.0.0.1:6379> set key1 "hello,world!" # 设置key1的值

OK

127.0.0.1:6379> get key1

"hello,world!"

127.0.0.1:6379> getrange key1 0 3 # 截取字符串 [0,3]

"hell"

127.0.0.1:6379> getrange key1 0 -1 # 获取全部字符串,和get key一样

"hello,world!"

# setrange 替换指定位置的字符串

127.0.0.1:6379> set key2 abcdefg

OK

127.0.0.1:6379> get key2

"abcdefg"

127.0.0.1:6379> setrange key2 1 BCDEFG # 替换指定位置的字符串

(integer) 7

127.0.0.1:6379> get key2

"aBCDEFG"

######################################################################

# setex (set with expire) 设置过期时间

# setnx (set if not exist) 将key设置值为value,只有当key不存在时有效(在分布式锁中常常使用)

127.0.0.1:6379> setex key3 10 good # 设置key的值为good,10秒后过期

OK

127.0.0.1:6379> ttl key3 # 查看剩余时间

(integer) 6

127.0.0.1:6379> setnx key4 "redis" # 如果key4不存在,则创建key4,返回1

(integer) 1

127.0.0.1:6379> keys * # 此时key3已经过期

1) "key1"

2) "key4"

3) "key2"

127.0.0.1:6379> setnx key4 "mongoDB" # 如果key4存在,则创建失败,返回0

(integer) 0

127.0.0.1:6379> get key4

"redis"

######################################################################

# mset 同时设置多个值

# mget 同时获取多个值

# msetnx 只要有一个key已经存在,该操作就不会执行

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 同时设置多个值

OK

127.0.0.1:6379> mget k1 k2 k3 # 同时获取多个值

1) "v1"

2) "v2"

3) "v3"

127.0.0.1:6379> msetnx k1 v1 k4 v4 # msetnx是一个原子性的操作,要么一起成功,要么一起失败

(integer) 0

127.0.0.1:6379> get k4

(nil)

# 对象

# set user:1 {
    
    name:zhangsan, age:3}

# 设置一个user:1对象,值为json字符来保存一个对象

# 这里的key是一个巧妙的设计:user:{
    
    id}:{
    
    field},如此设计在Redis中是完全ok的

127.0.0.1:6379> mset user:1:name zhangsan user:1:age 20

OK

127.0.0.1:6379> mget user:1:name user:1:age

1) "zhangsan"

2) "20"

######################################################################

# getset 先get获取值再set赋值

127.0.0.1:6379> getset db redis # 如果不存在值,则返回nil

(nil)

127.0.0.1:6379> get db

"redis"

127.0.0.1:6379> getset db mongoDB # 如果存在值,则获取原来的值并设置新的值

"redis"

127.0.0.1:6379> get db

"mongoDB"

String summary:

String is the simplest data structure in Redis

The usage scenarios of String are as follows:

  • count value
  • Count the number of multiple units
  • Number of fans
  • object cache storage

3.4.2 List (list)

# lpush 将值值插入到列表头部(左)

# rpush 将值值插入到列表尾部(右)

# lrange 获取list中的值

127.0.0.1:6379> lpush list one # 将一个值或者多个值插入到列表头部(左)

(integer) 1

127.0.0.1:6379> lpush list two

(integer) 2

127.0.0.1:6379> lpush list three

(integer) 3

127.0.0.1:6379> lrange list 0 1 # 通过区间获取list中具体的值

1) "three"

2) "two"

127.0.0.1:6379> lrange list 0 -1 # 获取list中的值

1) "three"

2) "two"

3) "one"

127.0.0.1:6379> rpush list right # 将一个值或者多个值插入到列表尾部(右)

(integer) 4

127.0.0.1:6379> lrange list 0 -1

1) "three"

2) "two"

3) "one"

4) "right"

######################################################################

# lpop 移除左边的元素,即第一个元素

# rpop 移除右边的元素,即最后一个元素

127.0.0.1:6379> lpop list # 移除list的第一个元素

"three"

127.0.0.1:6379> lrange list 0 -1

1) "two"

2) "one"

3) "right"

127.0.0.1:6379> rpop list # 移除list的最后一个元素

"right"

127.0.0.1:6379> lrange list 0 -1

1) "two"

2) "one"

# lrem 移除指定的值

127.0.0.1:6379> lrange list 0 -1 # list中元素可以重复

1) "three"

2) "three"

3) "two"

4) "one"

127.0.0.1:6379> lrem list 2 three # 移除list中的2个three

(integer) 2

127.0.0.1:6379> lrange list 0 -1

1) "two"

2) "one"

######################################################################

# lindex 通过下标索引获取值

127.0.0.1:6379> lindex list 0 # 通过下标获得list中的某一个值

"two"

127.0.0.1:6379> lindex list 1

"one"

######################################################################

# llen 获取长度

127.0.0.1:6379> lrange list 0 -1

1) "three"

2) "two"

3) "one"

127.0.0.1:6379> llen list # 返回列表的长度

(integer) 3

######################################################################

# trim 修剪空格

# ltrim 截断并截取

127.0.0.1:6379> rpush mylist hello

(integer) 1

127.0.0.1:6379> rpush mylist hello1

(integer) 2

127.0.0.1:6379> rpush mylist hello2

(integer) 3

127.0.0.1:6379> rpush mylist hello3

(integer) 4

127.0.0.1:6379> ltrim mylist 1 2 # 通过下标截取指定的长度,这个list已经被改变了,只剩下截取的元素

OK

127.0.0.1:6379> lrange mylist 0 -1

1) "hello1"

2) "hello2"

######################################################################

#rpoplpush 移除列表的最后一个元素并将它移动到新的列表中

127.0.0.1:6379> lrange mylist 0 -1

1) "hello1"

2) "hello2"

3) "hello3"

127.0.0.1:6379> rpoplpush mylist myotherlist # 移除列表的最后一个元素并将它移动到新的列表中

"hello3"

127.0.0.1:6379> lrange mylist 0 -1 # 查看原来的列表

1) "hello1"

2) "hello2"

127.0.0.1:6379> lrange myotherlist 0 -1 # 查看新列表中确实有该值

1) "hello3"

######################################################################

# lset 将列表中指定下标的值替换为另外一个值,更新操作

127.0.0.1:6379> exists list # 判断这个列表是否存在

(integer) 0

127.0.0.1:6379> lset list 0 item # 如果不存在该列表,更新会报错

(error) ERR no such key

127.0.0.1:6379> lpush list hello

(integer) 1

127.0.0.1:6379> lrange list 0 0

1) "hello"

127.0.0.1:6379> lset list 0 world # 如果存在该列表,更新当前下表的值

OK

127.0.0.1:6379> lrange list 0 0

1) "world"

127.0.0.1:6379> lset list 1 good # 如果不存在该下标,则会报错

(error) ERR index out of range

######################################################################

# linsert 将某个具体的value插入到列表中某个元素的前面或后面

127.0.0.1:6379> lpush mylist hello

(integer) 1

127.0.0.1:6379> rpush mylist world

(integer) 2

127.0.0.1:6379> lrange mylist 0 -1

1) "hello"

2) "world"

127.0.0.1:6379> linsert mylist before world beautiful # 在world前面插入beautiful

(integer) 3

127.0.0.1:6379> lrange mylist 0 -1

1) "hello"

2) "beautiful"

3) "world"

127.0.0.1:6379> linsert mylist after world Yeah # 在world后面插入Yeah

(integer) 4

127.0.0.1:6379> lrange mylist 0 -1

1) "hello"

2) "beautiful"

3) "world"

4) "Yeah"

List summary:

All list commands start with l and are not case sensitive

Use the lpush rpop (first in first out) command to be a message queue, and use the lpush lpop (first in first out) command to be a stack

  • The list is actually a linked list, before Node after, left, right can insert values
  • If the key does not exist, create a new linked list
  • If the key exists, add content
  • If all values ​​are removed, an empty linked list also means that it does not exist
  • Inserting or changing values ​​on both sides is the most efficient, and inserting elements in the middle is relatively less efficient

3.4.3 Set (unordered collection)

# sadd 在集合中添加元素

# smembers 查看指定set的所有值

# sismember 判断某个值是否在set集合中

127.0.0.1:6379> sadd myset hello # set集合中添加元素

(integer) 1

127.0.0.1:6379> sadd myset world

(integer) 1

127.0.0.1:6379> smembers myset # 查看指定set的所有值

1) "world"

2) "hello"

127.0.0.1:6379> sismember myset hello # 判断某个值是否在set集合中,是则返回1,不是则返回0

(integer) 1

127.0.0.1:6379> sismember myset helloworld

(integer) 0

######################################################################

# scard 获取个数

127.0.0.1:6379> scard myset # 获取set集合的个数

(integer) 2

127.0.0.1:6379> sadd myset hello # set集合中的值不能重复

(integer) 0

127.0.0.1:6379> sadd myset good

(integer) 1

127.0.0.1:6379> sadd myset morning

(integer) 1

127.0.0.1:6379> scard myset # 获取set集合的个数

(integer) 4

######################################################################

# srem 移除指定元素

127.0.0.1:6379> srem myset morning # 移除set集合中的morning元素

(integer) 1

127.0.0.1:6379> smembers myset

1) "good"

2) "world"

3) "hello"

######################################################################

# srandmember 随机抽取元素

127.0.0.1:6379> smembers randomset

1) "computer"

2) "iPhone"

3) "iPad"

4) "keyboard"

5) "mouse"

127.0.0.1:6379> srandmember randomset # 随机抽取一个元素

"keyboard"

127.0.0.1:6379> srandmember randomset

"iPhone"

127.0.0.1:6379> srandmember randomset

"computer"

127.0.0.1:6379> srandmember randomset 3 # 随机抽取指定个数的元素

1) "iPhone"

2) "iPad"

3) "keyboard"

127.0.0.1:6379> srandmember randomset 2

1) "computer"

2) "iPad"

######################################################################

# spop 删除指定key中随机的元素

127.0.0.1:6379> smembers randomset

1) "iPhone"

2) "computer"

3) "mouse"

4) "iPad"

5) "keyboard"

127.0.0.1:6379> spop randomset # 随机删除set集合中的一个元素

"iPad"

127.0.0.1:6379> spop randomset

"iPhone"

127.0.0.1:6379> smembers randomset

1) "computer"

2) "mouse"

3) "keyboard"

######################################################################

# smove 将一个指定的值移动到另一个set集合中

127.0.0.1:6379> sadd myset1 world

(integer) 1

127.0.0.1:6379> sadd myset1 good

(integer) 1

127.0.0.1:6379> sadd myset1 morning

(integer) 1

127.0.0.1:6379> sadd myset2 byebye

(integer) 1

127.0.0.1:6379> sadd myset2 seeyou

(integer) 1

127.0.0.1:6379> smove myset1 myset2 good # 将一个指定的值移动到另一个set集合中

(integer) 1

127.0.0.1:6379> smembers myset1

1) "world"

2) "morning"

3) "hello"

127.0.0.1:6379> smembers myset2

1) "good"

2) "seeyou"

3) "byebye"

######################################################################

# 微博和B站:共同关注(交集)

# 数字集合类:

# 交集:sinter

# 并集:sunion

# 差集:sdiff

127.0.0.1:6379> smembers key1

1) "b"

2) "a"

3) "c"

127.0.0.1:6379> smembers key2

1) "d"

2) "b"

3) "c"

127.0.0.1:6379> sdiff key1 key2 # 差集

1) "a"

127.0.0.1:6379> sdiff key2 key1 # 差集

1) "d"

127.0.0.1:6379> sinter key1 key2 # 交集:共同好友

1) "b"

2) "c"

127.0.0.1:6379> sunion key1 key2 # 并集

1) "a"

2) "c"

3) "b"

4) "d"

Set summary:

  • Set is an unordered non-repetitive collection, which is the biggest feature of Set collection
  • Set scope of application: common concern, common hobbies, second-degree friends, recommended friends (six degrees of separation theory)

3.4.4 Hash (Hash)

# hset 添加一个key-value键值对

# hget 获取指定key的value值

# hmset 添加多个key-value键值对

# hmget 获取多个key的value值

# hgetall 获取全部key-value键值对

# hdel 删除指定key

127.0.0.1:6379> hset myhash name zhangsan # set一个具体的key-value

(integer) 1

127.0.0.1:6379> hget myhash name # 获取指定key的value值

"zhangsan"

127.0.0.1:6379> hmset myhash name1 lisi name2 wangwu # set多个具体的key-value

OK

127.0.0.1:6379> hmget myhash name name1 name2 # 获取多个key的value值

1) "zhangsan"

2) "lisi"

3) "wangwu"

127.0.0.1:6379> hgetall myhash # 获取全部的key-value

1) "name"

2) "zhangsan"

3) "name1"

4) "lisi"

5) "name2"

6) "wangwu"

127.0.0.1:6379> hdel myhash name # 删除指定的key字段,对应的value值也消失了

(integer) 1

127.0.0.1:6379> hgetall myhash

1) "name1"

2) "lisi"

3) "name2"

4) "wangwu"

######################################################################

# hlen 获取字段数量

127.0.0.1:6379> hgetall myhash

1) "name1"

2) "lisi"

3) "name2"

4) "wangwu"

127.0.0.1:6379> hlen myhash # 获取hash表的字段数量

(integer) 2

127.0.0.1:6379> hmset myhash name3 aaa name4 bbb

OK

127.0.0.1:6379> hlen myhash # 获取hash表的字段数量

(integer) 4

######################################################################

# hexists 判断指定字段是否存在

127.0.0.1:6379> hexists myhash name # 判断指定字段是否存在,存在则返回1,不存在则返回0

(integer) 0

127.0.0.1:6379> hexists myhash name1

(integer) 1

######################################################################

# hkeys 只获得所有的key(field)

# hvals 只获得所有的value

127.0.0.1:6379> hkeys myhash # 只获得所有的key(field)

1) "name1"

2) "name2"

3) "name3"

4) "name4"

127.0.0.1:6379> hvals myhash # 只获得所有的value

1) "lisi"

2) "wangwu"

3) "aaa"

4) "bbb"

######################################################################

# hincrby 指定增量

# hsetnx 只在key指定的hash集中不存在指定的字段时,设置字段的值

127.0.0.1:6379> hset hash field 1

(integer) 1

127.0.0.1:6379> hincrby hash field 10 # 指定增量

(integer) 11

127.0.0.1:6379> hincrby hash field -15

(integer) -4

127.0.0.1:6379> hsetnx hash field hello # 如果存在则不能设置

(integer) 0

127.0.0.1:6379> hsetnx hash field1 hello # 如果不存在则可以设置

(integer) 1

Hash summary:

  • Hash is a collection of key-value pairs. It is not much different from the String type in essence. It is a mapping of String type.
  • Hash is more suitable for object storage, especially for frequently changing information such as user information, and String is more suitable for storing strings.

3.4.5 Zset (ordered set)

# zadd 添加一个值

# zrange 遍历所有值

127.0.0.1:127.0.0.1:6379> zadd zset 1 one # 添加一个值

(integer) 1

127.0.0.1:6379> zadd zset 2 two

(integer) 1

127.0.0.1:6379> zadd zset 3 three

(integer) 1

127.0.0.1:6379> zadd zset 4 four 5 five # 添加多个值

(integer) 2

127.0.0.1:6379> zrange zset 0 -1 # 遍历所有值

1) "one"

2) "two"

3) "three"

4) "four"

5) "five"

######################################################################

# 排序

# zrangebyscore 返回有序集合中指定sroce区间内的成员,score由低到高排序

# zrevrange 返回有序集合中指定sroce区间内的成员,score由高到低排序

127.0.0.1:6379> zadd salary 4000 zhangsan 5000 lisi 3000 wangwu # 添加3个用户

(integer) 3

127.0.0.1:6379> zrangebyscore salary -inf +inf # 显示全部用户,按score由低到高排序

1) "wangwu"

2) "zhangsan"

3) "lisi"

127.0.0.1:6379> zrevrange salary 0 -1 # 显示全部用户,按score由高到低排序

1) "lisi"

2) "zhangsan"

3) "wangwu"

127.0.0.1:6379> zrangebyscore salary -inf +inf withscores # 显示全部用户和score值升序排列

1) "wangwu"

2) "3000"

3) "zhangsan"

4) "4000"

5) "lisi"

6) "5000"

127.0.0.1:6379> zrangebyscore salary -inf 4000 withscores # 显示score小于等于4000的用户和score值升序排列

1) "wangwu"

2) "3000"

3) "zhangsan"

4) "4000"

######################################################################

# zrem 移除元素

# zcard 获取个数

127.0.0.1:6379> zrange salary 0 -1

1) "wangwu"

2) "zhangsan"

3) "lisi"

127.0.0.1:6379> zrem salary zhangsan # 移除有序集合中的指定元素

(integer) 1

127.0.0.1:6379> zrange salary 0 -1

1) "wangwu"

2) "lisi"

127.0.0.1:6379> zcard salary # 获取有序集合中的个数

(integer) 2

######################################################################

# zcount 获取数量

127.0.0.1:6379> zcount salary 3000 4000 # 获取指定区间的成员数量

(integer) 2

127.0.0.1:6379> zcount salary 3000 6000

(integer) 3

Zset summary:

  • Zset is similar to set in that it is a collection with no repeated elements
  • Zset adds the parameter score on the basis of set, and score can be repeated

For the rest of the API, if you need it in your work, you can check the official documents

Go to Redis Command Center

3.5 Three special data types

3.5.1 Geospatial location

How to realize the location of friends, nearby people, and calculation of taxi distance?

Redis's Geo was launched in Redis3.2 version. This function can calculate the geographical location information, the distance between two places, and the number of people in a radius.

Some data tests can be queried: city longitude and latitude query

geospatial has the following six commands:

  • GEOADD
  • GEODIST
  • GEOHASH
  • GEOPOS
  • GEORADIUS
  • GEORADIUSBYMEMBER

Geoadd

Rules: The two poles of the earth cannot be added directly. We usually download the city data and import it directly through the java program.

Parameters: latitude, longitude, name.

Valid longitudes are from -180 to 180 degrees.

Valid latitudes are from -85.05112878 degrees to 85.05112878 degrees.

# 经度纬度写反会报错
127.0.0.1:6379> geoadd China:city 39.904989 116.405285 Beijing
(error) ERR invalid longitude,latitude pair 39.904989,116.405285

# 添加一个地理位置
127.0.0.1:6379> geoadd China:city 116.405285 39.904989 Beijing
(integer) 1

127.0.0.1:6379> geoadd China:city 121.472644 31.231706 Shanghai
(integer) 1

127.0.0.1:6379> geoadd China:city 113.280637 23.125178 Guangzhou
(integer) 1

# 添加多个地理位置
127.0.0.1:6379> geoadd China:city 120.619585 31.299379 Suzhou 120.153576 30.287459 Hangzhou
(integer) 2

Geopos

Returns the location (longitude and latitude) of all elements at the given location from key.

geopos Get the current position, it must be a coordinate value.

# 获取一个地理位置的经纬度
127.0.0.1:6379> geopos China:city Beijing
1) 1) "116.40528291463851929"
   2) "39.9049884229125027"

# 获取多个地理位置的经纬度
127.0.0.1:6379> geopos China:city Shanghai Suzhou
1) 1) "121.47264629602432251"
   2) "31.23170490709807012"
2) 1) "120.61958581209182739"
   2) "31.29937942733126022"

Geodist

Returns the distance between two given positions.

If one of the two locations does not exist, the command returns NULL.

The parameter unit specifying the unit must be one of the following units:

  • m means the unit is meter.
  • km means the unit is kilometer.
  • mi means the unit is miles.
  • ft means the unit is feet.
# 获取北京到上海的直线距离
127.0.0.1:6379> geodist China:city Beijing Shanghai
"1067597.9668"

# 获取北京到上海的直线距离,以千米为单位
127.0.0.1:6379> geodist China:city Beijing Shanghai km
"1067.5980"

Georadius

With the given latitude and longitude as the center, return all the location elements contained in the key whose distance from the center does not exceed the given maximum distance.

Ranges can use one of the following units:

  • m means the unit is meter.
  • km means the unit is kilometer.
  • mi means the unit is miles.
  • ft means the unit is feet.

People nearby can realize it through this command.

# 以110 30经纬度为中心,寻找方圆2000km的城市
127.0.0.1:6379> georadius China:city 110 30 2000 km
1) "Guangzhou"
2) "Hangzhou"
3) "Suzhou"
4) "Shanghai"
5) "Beijing"

127.0.0.1:6379> georadius China:city 110 30 1000 km
1) "Guangzhou"
2) "Hangzhou"

# withdist 将位置元素与中心之间的距离也一并返回
127.0.0.1:6379> georadius China:city 110 30 1000 km withdist
1) 1) "Guangzhou"
   2) "831.2636"
2) 1) "Hangzhou"
   2) "976.8197"

# withcoord 将位置元素的经度和维度也一并返回
127.0.0.1:6379> georadius China:city 110 30 1000 km withcoord
1) 1) "Guangzhou"
   2) 1) "113.28063815832138062"
      2) "23.12517743834835215"
2) 1) "Hangzhou"
   2) 1) "120.15357345342636108"
      2) "30.28745790721532671"

# count 筛选个数
127.0.0.1:6379> georadius China:city 110 30 1000 km withcoord withdist count 1
1) 1) "Guangzhou"
   2) "831.2636"
   3) 1) "113.28063815832138062"
      2) "23.12517743834835215"

Georadiusbymember

Similar to georadius, the difference is that Georadius determines the center point by the input longitude and latitude, while Georadiusbymember determines the center point by the given position element.

127.0.0.1:6379> georadiusbymember China:city Beijing 1000 km
1) "Beijing"

127.0.0.1:6379> georadiusbymember China:city Shanghai 500 km
1) "Hangzhou"
2) "Suzhou"
3) "Shanghai"

Geohash

Returns a Geohash representation of one or more location elements, this command will return an 11 character Geohash string.

Convert the two-dimensional latitude and longitude into a one-dimensional string. The closer the two strings are, the closer the distance between the two places will be.

127.0.0.1:6379> geohash China:city Guangzhou Beijing
1) "ws0e9cb3yj0"
2) "wx4g0b7xrt0"

Geoprinciple

The underlying implementation principle of Geo is actually Zset, we can use the Zset command to operate GEO

# 查看地图中全部元素
127.0.0.1:6379> zrange China:city 0 -1
1) "Guangzhou"
2) "Hangzhou"
3) "Suzhou"
4) "Shanghai"
5) "Beijing"

# 移除指定元素
127.0.0.1:6379> zrem China:city Beijing
(integer) 1

127.0.0.1:6379> zrange China:city 0 -1
1) "Guangzhou"
2) "Hangzhou"
3) "Suzhou"
4) "Shanghai"

3.5.2 Hyperloglogs cardinality statistics

Redis version 2.8.9 has updated the Hyperloglogs data structure, and Hyperloglogs is used for cardinality statistics algorithms.

1. What is the cardinality

The number of unique elements in the set is the cardinality.

2. Features of Hyperloglogs

  • Hyperloglogs is a probabilistic data structure for counting non-repeating things (similar to set collections)
  • The advantage of Hyperloglogs is that it will not occupy more than 12KB of memory. From the perspective of memory, Hyperloglogs is the first choice.
  • There is a certain error in the Hyperloglogs algorithm, the error is less than 1%, about 0.81%, which can be ignored

test:

# pfadd 创建第一组元素mykey1
127.0.0.1:6379> pfadd mykey1 a b c d e f g
(integer) 1

# pfcount 统计mykey1元素的基数数量
127.0.0.1:6379> pfcount mykey1
(integer) 7

# pfadd 创建第二组元素mykey2
127.0.0.1:6379> pfadd mykey2 h i j k l m n a b c
(integer) 1

# pfcount 统计mykey2元素的基数数量
127.0.0.1:6379> pfcount mykey2
(integer) 10

# pfmerge 合并两组,并集为mykey3
127.0.0.1:6379> pfmerge mykey3 mykey1 mykey2
OK

# pfcount 统计并集mykey3元素的基数数量
127.0.0.1:6379> pfcount mykey3
(integer) 14

If fault tolerance is allowed, Hyperloglogs must be used ;

If fault tolerance is not allowed, just use set or your own data type.

3.5.3 Bitmaps

Bitmaps are mainly used in scenarios such as user check-in and user active days.

Bitmaps are a data structure that operates on binary bits for recording, and only has two states of 0 and 1.

test:

Use Bitmaps to record check-in from Monday to Sunday:

Monday: 1, Tuesday: 1, Wednesday: 1, Thursday: 0, Friday: 1, Saturday: 0, Sunday: 0

# setbit 设置位操作
127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 1
(integer) 0
127.0.0.1:6379> setbit sign 2 1
(integer) 0
127.0.0.1:6379> setbit sign 3 0
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 0
(integer) 0

Check whether a card is clocked in on a certain day: 1 means clocked in, 0 means not clocked in

# getbit 读取位操作
127.0.0.1:6379> getbit sign 0
(integer) 1
127.0.0.1:6379> getbit sign 2
(integer) 1
127.0.0.1:6379> getbit sign 6
(integer) 0

Statistical operation, counting the number of check-in days in a week

# bitcount 统计1的次数
127.0.0.1:6379> bitcount sign
(integer) 4

3.6 Transactions

When it comes to transactions, you will first think of the four characteristics (ACID) of relational database transactions:

  1. Atomicity: The atomicity of a transaction ensures that a set of update operations contained in a transaction are atomic and indivisible. To put it simply, transactions use atoms as the unit of work, either all of them are executed, or none of them are executed, and they will not stagnate in the middle.
  2. Consistency: The consistency of the transaction requires that the integrity constraints of the database must be satisfied before and after the transaction starts, and after the transaction is executed, the database will change from one consistent state to another consistent state.
  3. Isolation: The isolation of transactions requires that transactions be independent and isolated from each other, and the execution of a transaction cannot be affected by other transactions.
  4. Durability: The durability of a transaction requires that once a transaction is committed, its changes to the database are permanent and cannot be rolled back.

3.6.1 The concept of Redis transaction

Transaction Official Documentation

The nature of Redis transactions : a set of commands. All commands in a transaction will be serialized. During transaction execution, they will be executed in order and will not be inserted by other commands. That is: Reids' transactions are one-time , sequential , and exclusive execution commands.

Redis transaction characteristics

  • Redis transactions have no concept of isolation level
  • All commands are not directly executed in the transaction, and will only be executed when the execution command is initiated
  • Atomicity is guaranteed for a single Redis command, but atomicity is not guaranteed for transactions

Three phases of Redis transaction

  1. Open transaction (multi)
  2. command enqueued(...)
  3. Executing a transaction (exec)

3.6.2 Normal Execution Transaction (MULTI, EXEC)

# 开启事务
127.0.0.1:6379> multi
OK

# 命令入队
127.0.0.1:6379(TX)> set key1 value1
QUEUED

127.0.0.1:6379(TX)> set key2 value2
QUEUED

127.0.0.1:6379(TX)> get key1
QUEUED

127.0.0.1:6379(TX)> get key2
QUEUED

# 执行事务
127.0.0.1:6379(TX)> exec
1) OK
2) OK
3) "value1"
4) "value2"

3.6.3 Abandon transaction (DISCARD)

# 开启事务
127.0.0.1:6379> multi
OK

127.0.0.1:6379(TX)> sadd myset set1
QUEUED

127.0.0.1:6379(TX)> sadd myset set2
QUEUED

# 取消事务
127.0.0.1:6379(TX)> discard
OK

# 事务队列中的命令都不会被执行
127.0.0.1:6379> smembers myset
(empty array)

3.6.4 Exceptions during transaction execution

1. Compilation exception

If the code is abnormal and the command is wrong, all commands in the transaction will not be executed.

127.0.0.1:6379> multi
OK

127.0.0.1:6379(TX)> set k1 v1
QUEUED

127.0.0.1:6379(TX)> set k2 v2
QUEUED

127.0.0.1:6379(TX)> set k3 v3
QUEUED

# 命令错误,入队时就会报错
127.0.0.1:6379(TX)> getset k3
(error) ERR wrong number of arguments for 'getset' command

127.0.0.1:6379(TX)> set k4 v4
QUEUED

127.0.0.1:6379(TX)> set k5 v5
QUEUED

# 执行事务时也会报错
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.

# 所有的命令都不会被执行
127.0.0.1:6379> get k5
(nil)

2. Runtime exception

If there is a syntax error in the transaction queue, other commands can be executed normally when the command is executed, and the wrong command will throw an exception.

127.0.0.1:6379> set key "hello"
OK

127.0.0.1:6379> multi
OK

# 命令入队时不报错,但执行时会报错
127.0.0.1:6379(TX)> incr key
QUEUED

127.0.0.1:6379(TX)> set key2 value2
QUEUED

127.0.0.1:6379(TX)> set key3 value3
QUEUED

127.0.0.1:6379(TX)> get key
QUEUED

# 虽然第一条命令报错了,但是依旧正常执行成功了
127.0.0.1:6379(TX)> exec
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
4) "hello"

127.0.0.1:6379> get key2
"value2"

127.0.0.1:6379> get key3
"value3"

3.6.5 Monitoring (WATCH)

Pessimistic lock: very pessimistic, thinking that there will be problems at any time, and no matter what you do, it will be locked.

Optimistic locking: very optimistic, thinking that there will be no problems at any time, so it will not be locked. When updating the data, it will be judged whether someone has modified the data during this period. That is: get the version and compare the version when updating.

test:

1. Normal execution is successful:

127.0.0.1:6379> set balance 10000
OK

127.0.0.1:6379> set expend 0
OK

# 监视balance对象
127.0.0.1:6379> watch balance
OK

127.0.0.1:6379> multi
OK

127.0.0.1:6379(TX)> decrby balance 100
QUEUED

127.0.0.1:6379(TX)> incrby expend 100
QUEUED

# 事务正常结束,数据期间没有发生变动,这个时候就是正常执行成功
127.0.0.1:6379(TX)> exec
1) (integer) 9900
2) (integer) 100

2. Execution failed

To test multithreading, watch can be used as an optimistic lock operation of Redis.

# 第一个线程
127.0.0.1:6379> watch balance
OK

127.0.0.1:6379> multi
OK

127.0.0.1:6379(TX)> decrby balance 200
QUEUED

127.0.0.1:6379(TX)> incrby expend 200
QUEUED

# 在第二个线程充值完100元后第一个线程会执行失败
127.0.0.1:6379(TX)> exec
(nil)

######################################################################

# 第二个线程
127.0.0.1:6379> get balance
"9900"

# 在第一个线程未执行前给balance充值100127.0.0.1:6379> incrby balance 100
(integer) 10000

If the modification fails, just get the latest value.

# 如果发现失误执行失败,先unwatch解锁
127.0.0.1:6379> unwatch
OK

# 获取最新的值,再次监视balance (select version)
127.0.0.1:6379> watch balance
OK

127.0.0.1:6379> multi
OK

127.0.0.1:6379(TX)> decrby balance 500
QUEUED

127.0.0.1:6379(TX)> incrby expend 500
QUEUED

# 对比监视的值是否发生变化,如果没有变化,那么可以执行成功,否则就执行失败
127.0.0.1:6379(TX)> exec
1) (integer) 9500
2) (integer) 600

Thanks for reading! The above is an explanation of the basic knowledge of Redis. If you don’t understand or have mistakes, please discuss in the comment area!

Students who have finished learning Redis can continue to learn Jedis!
Introduction and use of Jedis in Redis advanced chapter

Guess you like

Origin blog.csdn.net/wyc837279588/article/details/127602056