##redis Basics###

redis Basics

redis

The following is excerpted from the Chinese official website of redis: http://www.redis.cn/

Redis is an open source (BSD licensed) in memory data structure storage system, which can be used as * * database, cache and message middleware. It supports many types of data structures, such as stringshasheslistssetssorted sets And range query * *, bitmapshyperloglogs and geospatial Index radius query. Redis has built-in replicationLua scriptingLRU eventtransactions And different levels of Disk persistence , and passed Redis Sentinel And automatic Partition (Cluster) Provide high availability = = > it can be used as a cluster

Redis-Key

The key value of redis is a binary safety belt, and any binary sequence can be used as the key value. From string to jpeg file content, or even an empty string.

127.0.0.1:6379> exists name			#Judge whether the key exists. 1 means it exists and 0 means it does not exist
(integer) 1
127.0.0.1:6379> exists name2
(integer) 0
127.0.0.1:6379> clear
127.0.0.1:6379> move name 1			#Move the key from the current database to the database, which is indicated later
(integer) 1
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
1) "name"
127.0.0.1:6379[1]> expire name 10	#Set the timeout for this key
(integer) 1
127.0.0.1:6379[1]> ttl name			#Get the valid time of this key, - 2 means it has timed out and does not exist
(integer) -2
127.0.0.1:6379[1]> get name
(nil)
127.0.0.1:6379[1]> set name 7
OK
127.0.0.1:6379[1]> type name		#View the data type of the key
string

Run redis

docker run

-d start as a daemon. Daemon: refer to the daemon thread of java. Even if ctrl+c exits, it will not stop the operation of this container

– name set name. All commands requiring id access can be replaced by name

The error is reported here because I have run this redis before. If I use docker images, I will see that the myredis container already exists

mirana@Mo Xiaoqi:/mnt/c/Users/Mo Xiaoqi $ docker run -d --name myredis redis
docker: Error response from daemon: Conflict. The container name "/myredis" is already in use by container "3bfc98b3236f47bd46475bb3213bb0bef03782b01e2f3c1a9bde90899333af45". You have to remove (or rename) that container to be able to reuse that name.
See 'docker run --help'.

So:

Use the restart command to run the container directly

mirana@Mo Xiaoqi:/mnt/c/Users/Mo Xiaoqi $ docker restart myredis
myredis

Enter redis interaction

mirana@Mo Xiaoqi:/mnt/c/Users/Mo Xiaoqi $ docker exec -it myredis redis-cli
127.0.0.1:6379>

There is a crooked building here:

Why is the redis port 6379 by default?

Take out your mobile phone - tap the keyboard - this is actually a star name loved by the redis author. If you are interested, you can search it

redis basic commands

redis has 16 databases in total

Find the path of redis

mirana@Mo Xiaoqi:/mnt/c/Users/Mo Xiaoqi $ whereis redis
redis: /etc/redis

Enter the corresponding path

mirana@Mo Xiaoqi:/mnt/c/Users/Mo Xiaoqi $ cd /etc/redis

Display the contents of the current directory and open the redis.conf configuration file

You can see this line. redis has 16 databases by default. You can modify the configuration file to define it yourself

[the external link image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-OsqN49a2-1631719421521)(image-20210911120530196.png)]

select

Switch database

redis is the 0th database by default. You can switch databases through the select command

For example, switch to the third database

127.0.0.1:6379> select 3  
OK

dbsize

View the number of key s in the current database

127.0.0.1:6379[3]> dbsize   
(integer) 0
127.0.0.1:6379[3]> set name 77  #set
OK
127.0.0.1:6379[3]> set name2 88
OK
127.0.0.1:6379[3]> dbsize
(integer) 2

keys

View all key s in the current database

127.0.0.1:6379[3]> keys *   
1) "name2"
2) "name"

flushdb

Empty the current database

127.0.0.1:6379[3]> flushdb 
OK
127.0.0.1:6379[3]> dbsize
(integer) 0

flushall

Light empty all databases

For the following test, first the third database plug value, then the 0 database plug value, and then flush dB

Then you will see that both the 0 database and the 3 database are empty

127.0.0.1:6379[3]> set name 777
OK
127.0.0.1:6379[3]> select 0
OK
127.0.0.1:6379> set name 77777
OK
127.0.0.1:6379> dbsize
(integer) 1
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> dbsize
(integer) 0
127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> dbsize
(integer) 0

redis data structure

redis has eight data structures, including five common data structures and three special data structures

Five common data structures:

String

The value of value can be any kind of string, including binary data. The maximum can not exceed 512MB. In addition to strings, you can also use numbers, pictures or serialized objects.

Usage scenario

  • Counter

  • Count multi unit quantity

  • Number of fans

  • Object cache and storage

  • Distributed lock

Common commands:

127.0.0.1:6379> set key name
OK
**************set Support similar json The writing method of is as follows****************
127.0.0.1:6379> set user:1:name 77
OK
127.0.0.1:6379> set user:1:age 18
OK
127.0.0.1:6379> keys *
1) "user:1:age"
2) "user:1:name"
******************************
127.0.0.1:6379> exists name	#Determine whether this key exists
(integer) 0
127.0.0.1:6379> append key 77 #Append after value of key
(integer) 6
127.0.0.1:6379> get key
"name77"
127.0.0.1:6379> strlen key	 #Get the length of the value of the key
(integer) 6
127.0.0.1:6379> append key ",today"
(integer) 12
127.0.0.1:6379> strlen key
(integer) 12
127.0.0.1:6379> append key1 zhangsan	#When append, set if the key does not exist
(integer) 8
127.0.0.1:6379> keys *
1) "key1"
2) "key"

incr,decr,incrby,decrby

Atomic increment / decrement

127.0.0.1:6379> set viewcount 0
OK
127.0.0.1:6379> get viewcount
"0"
127.0.0.1:6379> incr viewcount	 	#Increment the value of this key
(integer) 1
127.0.0.1:6379> get viewcount
"1"
127.0.0.1:6379> incr viewcount
(integer) 2
127.0.0.1:6379> get viewcount
"2"
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set view 0
OK
127.0.0.1:6379> incrby view 2	#Increment the value of this key in steps
(integer) 2
127.0.0.1:6379> incrby view 2
(integer) 4
127.0.0.1:6379> get view
"4"
127.0.0.1:6379> set total 100
OK
127.0.0.1:6379> decr total		#Decrement the value of this key
(integer) 99
127.0.0.1:6379> decr total
(integer) 98
127.0.0.1:6379> get total
"98"
127.0.0.1:6379> decrby total 2	#Decrement the value of this key in steps
(integer) 96
127.0.0.1:6379> decrby total 2
(integer) 94
127.0.0.1:6379> get total
"94"

incr and decr are atomic operations

getrange

Get string

Command format: GETRANGE key start end

When start end is 0 - 1, all are returned

127.0.0.1:6379> set return hello,77,fignting
OK
127.0.0.1:6379> get return
"hello,77,fignting"
127.0.0.1:6379> getrange return 0 2
"hel"
127.0.0.1:6379> getrange return 0 -1 
"hello,77,fignting"
setex

set with expire: set a value for this key and set the expiration time

Command format: SETEX key seconds value

127.0.0.1:6379> setex name 10 7
OK
127.0.0.1:6379> ttl name #Get valid time of key
(integer) 8
127.0.0.1:6379> get name
"7"
setnx

If this key does not exist, it will be set

127.0.0.1:6379> setnx address shenzhen
(integer) 1
127.0.0.1:6379> keys *
1) "return"
2) "address"
3) "age"
127.0.0.1:6379> setnx age 19  #If this key exists, it will fail
(integer) 0
Using setnx to realize distributed lock

It is often used for distributed locks, but it is better to implement it with zk. Because zk has temporary nodes, the mechanism is similar to sql for update. Once the link is hung, the lock will be automatically released. There is no need to consider the following scenarios in redis

There are several points to pay attention to when setnx implements distributed locks:

1) To set the timeout

Prevent setnx... Business code... From releasing the lock. If the jvm hangs when the business code is executed, this will be a deadlock

2) When releasing the lock, judge whether the value of set is the value you set

​ jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

try{

/ / business code

}catch{

/ / exception handling

}finally{

/ / release del key

}

If you set a timeout of 5s when you set NX and the business code executes for 6s, the lock is released within 1s of the timeout. At this time, another thread resets the value. At this time, your code finally releases someone else's lock. Therefore, you need to ensure that you release your own lock (you can set a uuid for the key through redis, and then obtain the value of the key in finally, and then judge whether it is the uuid you set)

3) Or the last question

finally Code:

​ getkey

​ delkey

If you just get the getkey and another thread comes right after you get it, your del will be someone else's lock again.

Therefore, it is necessary to ensure that get and del are the same instruction. At this time, java code can not be used. lua script should be used

For more notes, refer to the blog: https://mp.weixin.qq.com/s/qJK61ew0kCExvXrqb7-RSg

mset & mget,msetnx

Batch setting and obtaining

msetnx is the same as setnx, atomic operation of batch setting

127.0.0.1:6379> mset name 77 age 17
OK
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> msetnx age 19 collage xidian
(integer) 0
getset

If it does not exist, nil is returned

If it exists, the original value is returned and updated

127.0.0.1:6379> getset db redis
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mysql
"redis"
127.0.0.1:6379> get db
"mysql"
scan

The time complexity is O(1)

Command format SCAN cursor [MATCH pattern] [COUNT count]

The following is an excerpt from the Chinese official website of redis, with some changes

Command interpretation
  • SCAN This command is used to iterate over the key set in the current database.
  • SSCAN Command is used to iterate over elements in a SET set.

  • HSCAN Command is used to iterate over key value pairs in a Hash type.

  • ZSCAN The command is used to iterate over the elements in the SortSet set and the scores corresponding to the elements

The four commands listed above support incremental iteration, and they only return a small number of elements each time they are executed, so these commands can be used in the production environment without like KEYS perhaps SMEMBERS The problem caused by the command may block the server.

however, SMEMBERS The command can return all the elements currently contained in the set key, but for incremental iterative commands such as SCAN, the set elements may be modified in the process of incremental iteration, which can not provide complete and accurate guarantee for the return value.

SCAN, SSCAN, HSCAN and ZSCAN The four commands work in a very similar way. It should be noted that SSCAN, HSCAN ,ZSCAN The first parameter of the command is always a key; SCAN The command does not need to provide any key in the first parameter, because it iterates over all keys in the current database.

SCAN The command is a cursor based iterator. This means that every time the command is called, the cursor returned from the previous call needs to be used as the cursor parameter of the call, so as to continue the previous iteration process

When SCAN When the cursor parameter of the command is set to 0, the server will start a new iteration. When the server returns a cursor with a value of 0 to the user, it indicates that the iteration has ended.

Return results

The SCAN incremental iteration command does not guarantee that a given number of elements will be returned every time it is executed, or even zero elements may be returned. However, as long as the cursor returned by the command is not 0, the application should not regard the iteration as the end.

However, the number of elements returned by the command always conforms to certain rules. For a large data set, the incremental iterative command may return dozens of elements at most at a time; For a sufficiently small data set, if the bottom layer of the data set is represented as coded data structures (small sets, hashes and sorted sets), the incremental iteration command will return all elements in the data set in one call.

If necessary, the user can specify the maximum value of the returned element for each iteration through the COUNT option provided by the incremental iteration command. The SCAN incremental iteration command does not guarantee that a given number of elements will be returned every time it is executed, or even zero elements may be returned. However, as long as the cursor returned by the command is not 0, the application should not regard the iteration as the end.

However, the number of elements returned by the command always conforms to certain rules. For a large data set, the incremental iterative command may return dozens of elements at most at a time; For a sufficiently small data set, if the bottom layer of the data set is represented as coded data structures (small sets, hashes and sorted sets), the incremental iteration command will return all elements in the data set in one call.

If necessary, the user can specify the maximum value of the returned element for each iteration through the COUNT option provided by the incremental iteration command.

Parameter count

For the incremental iteration command, the number of elements returned in each iteration is not guaranteed. We can use the COUNT option to adjust the behavior of the command to a certain extent. The function of the COUNT option is to let the user tell the iteration command how many elements should be returned from the dataset in each iteration. Using the COUNT option is equivalent to a prompt for incremental iterative commands. In most cases, this prompt effectively controls the number of returned values.

  • The default value of the COUNT parameter is 10.
  • When the dataset is relatively large, if the MATCH option is not used, the number of elements returned by the command is usually the same as or slightly more than that specified by the COUNT option.
  • When iterating over an integer set (intset, a small set consisting only of integer values) or a compressed list (ziplost, a small hash composed of different values or a small ordered set), the incremental iteration command usually ignores the value specified by the count option and returns all elements contained in the dataset to the user in the first iteration. (that is, if the amount of data is too small, the count command will fail)

Note: * * the same COUNT value is not used in each iteration * *. Users can change the COUNT value according to their needs in each iteration. Just remember to use the cursor returned from the last iteration in the next iteration.

Therefore, it is better not to use the scan command for paging and other functions. For similar pit stepping experience, please see the blog:

https://blog.csdn.net/zjcsuct/article/details/108138876

List

Application scenario:

It can be used to implement stack (lpush, lpop), queue, message queue (lpush, rpop) and blocking access (lpush and rpop: brpop and blpop commands with blocking access can be used to implement)

  • before node after
  • Both left and right segments can be inserted
  • If the key does not exist, create a new one
  • If the key exists, add it
  • If all are removed, it is an empty linked list and does not exist
  • Inserting or changing on both sides is the most efficient. If you want to access the elements in the specified location, the efficiency is low
lpush & lrange

You can imagine writing from the left (chain header)

127.0.0.1:6379> lpush list one two	   #It can be seen that first in and last out
(integer) 2
127.0.0.1:6379> lrange list 0 1
1) "two"
2) "one"
127.0.0.1:6379> lrange list 0 2
3) "two"
4) "one"
127.0.0.1:6379> lrange list 0 -1		#Get the value of the list, or get the value of a specific location according to the index. If 0 - 1, get all
1) "two"
2) "one"
rpush

Write from the right (end of linked list)

127.0.0.1:6379> rpush list zero
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "zero"
lpop & rpop
127.0.0.1:6379> lpop list  #Remove the first element of the list
"two"
127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "zero"
127.0.0.1:6379> rpop list	#Remove the last value of the list
"zero"
127.0.0.1:6379> lrange list 0 -1
1) "one"
lindex

Gets the value of the specified element

127.0.0.1:6379> lpush list zero one two three
(integer) 4
127.0.0.1:6379> lindex list 1
"two"
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "zero"
llen

Get list length

127.0.0.1:6379> llen list
(integer) 4
lrem

Remove the specified number of value s in the list

Command format: LREM key count value

127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "zero"
5) "zero"
6) "zero"
7) "1"
127.0.0.1:6379> lrem list 6 1
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "zero"
5) "zero"
6) "zero"
127.0.0.1:6379> lrem list 2 zero
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "zero"
ltrim

Intercept list

Command format: LTRIM key start stop

127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "zero"
127.0.0.1:6379> ltrim list 0 1
OK
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
rpoplpush

Remove the last element of the list and lpush to a new list

127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "two"
3) "three"
4) "four"
127.0.0.1:6379> rpoplpush list otherlist
"four"
127.0.0.1:6379> lrange otherlist 0 -1
1) "four"
exists & lset

lset:

Replaces the value of the specified subscript in the list

First judge whether the list exists. If it does not exist, an error will be reported

Then judge whether the specified subscript exists. If it does not exist, an error will be reported

127.0.0.1:6379> exists list2	#Determine whether the list exists
(integer) 0
127.0.0.1:6379> lset list2 0 77	#If this list does not exist, an error will be reported
(error) ERR no such key
127.0.0.1:6379> lpush list2 1
(integer) 1
127.0.0.1:6379> lset list2 1 77	#If this subscript does not exist, an error will also be reported
(error) ERR index out of range
127.0.0.1:6379> lset list2 0 77	#If it exists, it will be updated
OK
127.0.0.1:6379> lrange list2 0 -1
1) "77"
linsert

Inserts a specific value before or after the specified element in the list

127.0.0.1:6379> lrange list2 0 -1
1) "77"
127.0.0.1:6379> linsert list2 before 77 88
(integer) 2
127.0.0.1:6379> lrange list2 0 -1
1) "88"
2) "77"
127.0.0.1:6379> linsert list2 after 77 66
(integer) 3
127.0.0.1:6379> lrange list2 0 -1
1) "88"
2) "77"
3) "66"

Hash

It is essentially a k-map structure, which can be used to store objects that often need to be changed. string is OK, but the best way is to use hash

hset & hget

Store / read a key in the hash

Hset can also store multiple key s in the hash. In the version after Redis 4.0.0, hmset has been discarded. Use hset

127.0.0.1:6379> hset myhash name 77 age 17 address shenzhen
(integer) 3
127.0.0.1:6379> hget myhash name
"77"
hmset & hmget

Batch set/get

As per Redis 4.0.0, HMSET is considered deprecated. Please prefer HSET in new code. ------- from the official website of redis

127.0.0.1:6379> hmset myhash name 88 name2 99
OK
127.0.0.1:6379> hmget myhash name name2
1) "88"
2) "99"
127.0.0.1:6379> hsetnx myhash name 00
(integer) 0
hsetnx

When the key does not exist, set the key

If the key exists, the setting fails

setnx similar to string can be used for distributed

127.0.0.1:6379> hsetnx myhash name 00
(integer) 0
127.0.0.1:6379> hsetnx myhash name3 11
(integer) 1
hgetall

The time complexity is O(N). When there is too much data, hscan should be used to find it

127.0.0.1:6379> hgetall myhash
 1) "name"
 2) "88"
 3) "age"
 4) "17"
 5) "address"
 6) "shenzhen"
 7) "name2"
 8) "99"
 9) "name3"
10) "11"
hscan

Refer to scan command

127.0.0.1:6379> hscan myhash 111 match name count 1
1) "0"
2) 1) "name"
   2) "88"
hdel
127.0.0.1:6379> hdel myhash name2 name3
(integer) 2
127.0.0.1:6379> hgetall myhash
1) "name"
2) "88"
3) "age"
4) "17"
5) "address"
6) "shenzhen"
hlen
127.0.0.1:6379> hlen myhash
(integer) 3
hexists
127.0.0.1:6379> hexists myhash name
(integer) 1
hkeys &hvals
127.0.0.1:6379> hkeys myhash
1) "name"
2) "age"
3) "address"
127.0.0.1:6379> hvals myhash
1) "88"
2) "17"
3) "shenzhen"
hincrby
127.0.0.1:6379> hincrby myhash age 1
(integer) 18
127.0.0.1:6379> hget myhash age
"18"

Set

Non repetitive

Application scenario

  • Random number
  • Union, difference and intersection (such as social needs)
sadd

Batch add

127.0.0.1:6379> sadd name1 77 88
(integer) 1
smembers

View all elements of set, the same as hget command, with low efficiency. sscan is recommended

127.0.0.1:6379> smembers name1
1) "77"
2) "88"
sismember

Check whether this element exists in the set

127.0.0.1:6379> sismember name1 99
(integer) 0
scard

View the total number of elements in the set

127.0.0.1:6379> scard name1
(integer) 2
srem

Removes the specified element from the set

127.0.0.1:6379> srem name1 88(integer) 1
srandmember

Randomly obtain the specified number of elements in the set

127.0.0.1:6379> srandmember name1 2
1) "77"
2) "88"
127.0.0.1:6379> srandmember name1 2
1) "99"
2) "88""
spop

Randomly remove the specified number of elements in the set

127.0.0.1:6379> spop name1 1
1) "77"
127.0.0.1:6379> smembers name1
1) "88"
2) "99"
smove

Moves the specified element in one set to another set

127.0.0.1:6379> sadd set1 11 22 33
(integer) 3
127.0.0.1:6379> sadd set2 99
(integer) 1
127.0.0.1:6379> smove set1 set2 33
(integer) 1
127.0.0.1:6379> smembers set2
1) "33"
2) "99"
127.0.0.1:6379> smembers set1
1) "11"
2) "22"
sdiff & sinter & sunion

sdiff: get the difference set of two sets

sinter: get the intersection of two set s

sunion: get the union of two set s

127.0.0.1:6379> smembers set1
1) "11"
2) "22"
3) "33"
127.0.0.1:6379> smembers set2
1) "33"
2) "99"
127.0.0.1:6379> sdiff set1 set2
1) "11"
2) "22"
127.0.0.1:6379> sinter set1 set2
1) "33"
127.0.0.1:6379>  sunion set1 set2
1) "11"
2) "22"
3) "33"
4) "99"

ZSet

Ordered set

Application scenario:

  • Ranking: ranking list, news ranking, name ranking, phone number ranking
  • Weighted Sorting

zadd & zrange

zadd: add

zrange: check the elements in the set. 0 - 1 is to return all. zscan is more efficient

127.0.0.1:6379> zadd myzset 0 77 1 88
(integer) 2
127.0.0.1:6379> zrange myzset 0 -1
1) "77"
2) "88"
127.0.0.1:6379>  zadd myzset 5 99 4 10
(integer) 2
127.0.0.1:6379> zrange myzset 0 -1
1) "77"
2) "88"
3) "10"
4) "99"
zrangebyscore & zrevrangebyscore

Command format

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]

zrangebyscore: score returns in ascending order within the specified interval (both sides can specify > or ≥, < or ≤). It can be used as paging, and the return quantity can be specified

zrevrangebyscore: the score is returned in descending order

127.0.0.1:6379> zadd myzset 1 one 2 two 3 three
(integer) 3
127.0.0.1:6379> zrange myzset 0 -1
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> zrangebyscore myzset -inf +inf
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> zrangebyscore myzset -inf +inf withscores
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
127.0.0.1:6379> zrevrangebyscore myzset +inf -inf
1) "three"
2) "two"
3) "one"
zrangebylex & zrevrangebylex

ZRANGEBYLEX key min max [LIMIT offset count]
ZREVRANGEBYLEX key max min [LIMIT offset count]

Command description: the premise of these two commands is that the score weight in zset must be the same

zrangebylex: sort in ascending order according to dictionary order (both sides can specify > or ≥, < or ≤). You can specify an interval or pagination, and specify the number of returned entries

zrevrangebylex: descending

127.0.0.1:6379> zadd myzset 0 a 0 c 0 b
(integer) 3
127.0.0.1:6379>  zrangebylex myzset - +
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> zadd names 0 Toumas 0 Jake 0 Bluetuo 0 Gaodeng 0 Aimini 0 Aidehua
(integer) 6
127.0.0.1:6379> zrevrangebylex names + -
1) "Toumas"
2) "Jake"
3) "Gaodeng"
4) "Bluetuo"
5) "Aimini"
6) "Aidehua"
zrem

Removes the specified element of zset

127.0.0.1:6379> zrem myzset zero
(integer) 1
zcard

Returns the total number of elements in zset

127.0.0.1:6379> zcard myzset
(integer) 3
zcount

Returns the number of elements in the specified score range

127.0.0.1:6379> zcount myzset 1 3
(integer) 3

Three special data structures:

Geospatial

The underlying implementation principle is zset, so all zset instructions can be used. You can see the last argument

Application scenario:

  • Geographic location, storing geographic location information
  • Calculate the distance between the two places
  • See people nearby
geoadd

add to

127.0.0.1:6379> geoadd china 121.43333 34.50000 shanghai 117.20000 39.13333 tianjing
(integer) 2
geodist

To calculate the distance between two places, km, m, mi, ft can be specified

127.0.0.1:6379> geodist china beijing shanghai
"748346.9287"
geopos

Returns the latitude and longitude of the specified city

127.0.0.1:6379> geoadd china 116.41667 39.91667 beijing
(integer) 1
127.0.0.1:6379> geopos china beijing
1) 1) "116.41667157411575317"
   2) "39.91667095273589183"
georadius

Take the specified latitude and longitude as the center of the circle and specify the radius to find. withcoord can return the precision of the result, and withlist returns the distance from the result to the center of the circle

127.0.0.1:6379> geoadd china 106.45000 29.56667 chongqing
(integer) 1
127.0.0.1:6379> georadius china 110 30 1000 km
1) "chongqing"
127.0.0.1:6379> georadius china 110 30 1000 km withcoord withdist
1) 1) "chongqing"
   2) "346.0548"
   3) 1) "106.4500012993812561"
      2) "29.56666939001875249"
127.0.0.1:6379> georadius china 110 30 1000 km count 1
1) "chongqing"
georadiusbymember

As above, change the center of the circle to the specified city

127.0.0.1:6379> georadiusbymember china beijing  1000 km
1) "shanghai"
2) "tianjing"
3) "beijing"
4) "xian"
geohash

Returns the hash value of the specified element

127.0.0.1:6379> geohash china beijing
1) "wx4g14s53n0"
Operate with zset command
127.0.0.1:6379> zrange china 0 -1
1) "chongqing"
2) "xian"
3) "shanghai"
4) "tianjing"
5) "beijing"
127.0.0.1:6379> zrem china tianjing
(integer) 1

Hyperloglog

Although the data structure of cardinality statistics algorithm can also be realized through other data types, the memory occupied by Hyperloglog is fixed. Using the technology of 2 ^ 64 different elements, it only occupies 12kb memory.

Application scenario:

It is necessary to count non duplicate data, such as the UV of the website

0.81% error rate

pfadd

Add element

127.0.0.1:6379> pfadd test 0 1 1 2 3 3
(integer) 1
pfcount

View the total number of non repeating elements

127.0.0.1:6379> pfcount test
(integer) 4
pfmerge

Merge test and test2 into test3

127.0.0.1:6379> pfmerge test3 test test2
OK
127.0.0.1:6379> pfcount test3
(integer) 6

Bitmaps

Bit storage, bitmap, is a data structure. Are binary bits, only 0 and 1, so it is very space-saving and efficient.

Application scenario:

Statistics of scenarios with only two statuses: user information (active / inactive) and user login / not login

setbit

set

127.0.0.1:6379> setbit mybitmap 0 0
(integer) 0
127.0.0.1:6379> setbit mybitmap 1 0
(integer) 0
127.0.0.1:6379> setbit mybitmap 2 1
(integer) 0
127.0.0.1:6379> setbit mybitmap 3 1
(integer) 0
127.0.0.1:6379> setbit mybitmap 4 0
(integer) 0
getbit

Gets the value of the specified offset in the bitmap

127.0.0.1:6379> getbit mybitmap 3
(integer) 1
bitcount

Statistics

127.0.0.1:6379> bitcount mybitmap
(integer) 2

affair

Essence of redis transaction: a set of commands. All commands in a transaction will be serialized. During transaction execution, it is executed in sequence, and command requests submitted by other clients will not be inserted into the transaction execution command sequence.

redis transactions do not have the concept of mysql isolation level, so there are no dirty reads and illusions

Summarize redis transactions: execute a series of commands at one time, sequentially and exclusively

redis transaction execution process:

  • Open transaction: multi

  • A series of commands join the team (at this time, these commands are not directly executed, but will be executed only when the execution command is initiated)

  • Execute transaction / undo transaction exec

    A single redis command guarantees atomicity, but redis transactions do not guarantee atomicity! (see runtime exception)

Normal execution (multi XXX exec)

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set key1 77
QUEUED
127.0.0.1:6379(TX)> set key2 88
QUEUED
127.0.0.1:6379(TX)> set key3 99
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
3) OK
127.0.0.1:6379> keys *
1) "key2"
2) "key1"
3) "key3"

discard transaction

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set key1 11
QUEUED
127.0.0.1:6379(TX)> set key2 22
QUEUED
127.0.0.1:6379(TX)> set key3 33
QUEUED
127.0.0.1:6379(TX)> discard
OK
127.0.0.1:6379> get key3
(nil)

Optimistic lock (watch & unwatch)

Pessimistic lock

Very pessimistic, locked at any time. For example, java's synchronized

Optimistic lock

I'm optimistic that there will be no problem at any time, so I won't lock it. Judge whether someone has changed the data during this period during the update

​ java: cas

mysql: compare version when saving

​ redis: watch

watch & unwatch

watch :

Monitor the key. If the key is changed by other commands before the transaction is executed, the transaction will be interrupted.

Can be used to make optimistic locks

unwatch:

Cancel monitoring of key by watch

==========================Window 1 impersonate thread 1==========================
127.0.0.1:6379> set account1 1000
OK
127.0.0.1:6379> set account2 10
OK
127.0.0.1:6379> watch account1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby account1 200
QUEUED
127.0.0.1:6379(TX)> incrby account2 100
QUEUED
127.0.0.1:6379(TX)> exec	#When executing here, the value of account1 is modified, and the transaction fails
(nil)
127.0.0.1:6379> get account1	#The value of account1 is also 900 assigned by thread 2
"900"
==========================Window 2 Simulation thread 2==========================
127.0.0.1:6379> set account1 900(Rerun in execution of transaction account1 assignment)
OK

abnormal

Compiled exception (code problem / command error)

All commands within a transaction are not executed

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> setget k1 v2	#This order is wrong
(error) ERR unknown command `setget`, with args beginning with: `k1`, `v2`,
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.

Runtime exception (syntax error)

The wrong command will not be executed and an exception will be thrown

The remaining commands will still be executed. Therefore, redis transactions do not guarantee atomicity

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 key3 value3	#There is a mistake in this grammar
QUEUED
127.0.0.1:6379(TX)> set key4 value4
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (error) ERR syntax error
3) OK

jedis

Test:

The pom file is imported into jedis:

 <!--jedis-->
        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>

Writing test classes

     @Test
    public void connectTest(){
        Jedis jedis=new Jedis("127.0.0.1",6379);
        System.out.println(jedis.ping());
    }

function:

[the external link image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-zma2dtk-1631719421534) (image-20210913155114126. PNG)]

The api is basically the same as that of redis. There is no more repetition here

jedis implementation transaction

 @Test
    public void lock() {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        Transaction multi = jedis.multi();
        try {
            //Business code
            multi.set("key1", "77");
            multi.set("key2", "88");
            int i = 1 / 0;//Make a bug
            multi.exec();
            System.out.println(jedis.mget("key1", "key2"));
        } catch (Exception e) {
            //Abandon transaction
            multi.discard();
            //exception handling
            e.printStackTrace();
        } finally {
            //Close link
            jedis.close();
        }
    }

View redis after running:

127.0.0.1:6379> dbsize
(integer) 0

springboot integration

SpringBoot operation database: Spring data, jpa, jdbc, mongodb, redis

Spring boot 2. X later versions no longer use jedis, but lettuce

Jedis: with direct connection, multi-threaded operation is not safe. If you want to avoid it, use jedis pool, similar to BIO

lettuce: netty is adopted. The instance key is shared among multiple threads. There is no thread insecurity. Reduce thread data, more like NIO

Test:

pom file import:

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

Find the spring boot start redis related configuration classes in spring.factories (spring boot factory loading mechanism) of the springboot automatic configuration jar package:

org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\

Next, check RedisAutoConfiguration:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean(name = "redisTemplate")
	@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    //From here, we can customize our own RedisTemplate
	public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
		RedisTemplate<Object, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
		StringRedisTemplate template = new StringRedisTemplate();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

}

To view RedisProperties profile property classes:

[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-uGuuxLl0-1631719421537)(image-20210913170417095.png)]

Then we know that in the configuration file, the configuration attribute prefix of the jar package is spring.redis. For example:

spring.redis.host=127.0.0.1
spring.redis.database=3

Write test code:

@SpringBootTest
public class RedisTest {
    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    public void connectTest(){
        redisTemplate.opsForValue().set("name","77");
        redisTemplate.opsForValue().set("age","17");
        System.out.println(redisTemplate.opsForValue().get("name"));
    }
}

RestTemplate

serialize

redis publish and subscribe

Command test:

Message subscriber:

127.0.0.1:6379> subscribe channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
1) "message"
2) "channel1"
3) "hello"

Message sender:

127.0.0.1:6379> publish channel1 hello
(integer) 1

Principle:

Redis is implemented through C. redis implements PUBLISH and SUBSCRIBE functions through PUBLISH, SUBSCRIBE, PSUBSCRIBE and other commands.

After subscribing to a channel through the SUBSCRIBE command, a dictionary will be maintained in the redis service. The keys of the dictionary are channels, and the values of the dictionary are a linked list. All clients subscribing to this channel are saved in the linked list. The key of the SUBSCRIBE command is to add the client to the given channel subscription chain.

Send a message to subscribers through the PUBLISH command. Redis server will use the given channel as the key, find the linked list recording the subscription to this channel in the channel dictionary it maintains, traverse and PUBLISH the message to all subscribers.

Application scenario:

Real time message system

Subscribe and follow the system

Tags: Database Docker Redis lua

Posted on Wed, 15 Sep 2021 16:58:21 -0400 by Reef