1. Redis數(shù)據(jù)庫介紹
1.1 介紹
- 了解
NoSQL
數(shù)據(jù)庫
為什么要拋棄關系型數(shù)據(jù)庫绊谭?
為什么NoSQL
數(shù)據(jù)庫的讀寫速度遠超MySQL
?
有哪些常用的NoSQL
數(shù)據(jù)庫? - 安裝
Redis
數(shù)據(jù)庫
安裝Redis
數(shù)據(jù)庫
安裝Redis Desktop Manager
客戶端 -
Redis
相關配置
端口號汪拥、密碼达传、占用內(nèi)存大小、持久化方案等
1.2 Redis數(shù)據(jù)庫的安裝和配置
- 利用緩存優(yōu)化數(shù)據(jù)的讀寫
應用程序 - 緩存 - 數(shù)據(jù)庫 - 硬盤 - 高速緩存的應用案例
微博大V
的微博數(shù)據(jù)被存放于高速緩存中迫筑,普通人的數(shù)據(jù)存放于普通NoSQL
數(shù)據(jù)庫里宪赶。
門戶網(wǎng)站、電商網(wǎng)站脯燃、視頻網(wǎng)站首頁的內(nèi)容都需要緩存逊朽。
雙十一購物狂歡節(jié),訂單先被高速緩存曲伊,然后負載低谷期再寫入數(shù)據(jù)庫叽讳。
電商平臺秒殺、搶購業(yè)務需要用高速緩存來實現(xiàn)順序操作坟募。 -
Redis
簡介
Redis
是美國VMware
公司開源的NoSQL
數(shù)據(jù)庫產(chǎn)品岛蚤,基于Key-Value
存儲格式,可將數(shù)據(jù)保存在內(nèi)存或者硬盤中懈糯。
可以將使用頻率高的熱數(shù)據(jù)放到Redis
數(shù)據(jù)庫中涤妒,并保存到內(nèi)存中。 -
Redis
性能
Redis
是單線程模型的NoSQL
數(shù)據(jù)庫赚哗,由C
語言編寫她紫,官方提供的數(shù)據(jù)是可以達到100000+
的QPS
(每秒內(nèi)查詢次數(shù))。
-
Redis
安裝
(1) 參考文檔
(2) 安裝目錄
/usr/local/redis-5.0.5
(3) 啟動
# 直接啟動
? ~ redis-server
# 使用配置啟動
? ~ cd /usr/local/redis-5.0.7
? redis-5.0.7 redis-server redis.conf
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 5.0.7 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 8930
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
注釋:日志在控制臺中輸出屿储。
(4) 退出
查看redis
的pid
:ps aux|grep redis
結(jié)束進程:kill -15 pid
-
Redis
命令行客戶端
? ~ redis-cli
127.0.0.1:6379> select 0
OK
127.0.0.1:6379> set username scott
OK
127.0.0.1:6379> get username
"scott"
127.0.0.1:6379> del username
(integer) 1
127.0.0.1:6379> get username
(nil)
127.0.0.1:6379>
Redis
內(nèi)置了16
個邏輯庫(0-15
)贿讹,每個邏輯庫都是空的,可以通過select index
選擇邏輯庫够掠。
- 安裝圖形客戶端
RedisDesktopManager
是目前最優(yōu)秀的Redis
圖形客戶端工具民褂。
參考文檔:http://www.sohu.com/a/281755318_100264293
注意:RedisDesktopManager
是用來連接Redis
(redis-cli
),而不是啟動Redis
(redis-server
)疯潭。 -
Redis
的持久化
為了防止意外宕機丟失數(shù)據(jù)赊堪,Redis
提供了兩種持久化的方式。
(1)RDB
持久化
在指定的時間間隔內(nèi)將內(nèi)存中的數(shù)據(jù)集快照寫入磁盤竖哩,實際操作過程是fork
一個子進程哭廉,先將數(shù)據(jù)集寫入臨時文件,寫入成功后相叁,再替換之前的文件遵绰,用二進制壓縮存儲辽幌。
save 900 1 # 900秒內(nèi)寫入1次,則同步
save 300 10 # 300秒內(nèi)寫入10次街立,則同步
save 60 10000 # 60秒內(nèi)寫入10000次舶衬,則同步
(2) AOF
持久化
以日志的形式記錄服務器所處理的每一個寫埠通、刪除操作赎离,查詢操作不會記錄,以文本的方式記錄端辱,可以打開文件看到詳細的操作記錄梁剔。
# appendfsync no # 表示系統(tǒng)決定同步頻率
appendfsync everysec # 表示每秒同步一次
# appendfsync always # 表示每次修改數(shù)據(jù)都同步
-
Redis
配置參數(shù)(一)
序號 | 參數(shù) | 作用 |
---|---|---|
1 |
port |
端口號,默認6379
|
2 |
bind |
允許的IP 舞蔽,默認只允許本機訪問 |
3 |
timeout |
client 空閑多少秒后關閉連接荣病,默認0 代表無限制。 |
4 |
loglevel |
日志級別渗柿,分為:debug 个盆、verbose 、notice 朵栖、warning 颊亮,默認為notice
|
5 |
logfile |
日志文件地址 |
6 |
syslog-enabled |
將日志輸出到控制臺(yes ),將日志輸出到日志文件(no ) |
- 修改配置
(1) 修改
/usr/local/redis-5.0.7/redis.conf
bind 0.0.0.0
timeout 300
logfile "logs.log"
syslog-enabled no
bind 127.0.0.1
表示只有當前主機可以訪問當前Redis
服務器陨溅。bind 0.0.0.0
表示任何主機都能訪問當前Redis
服務器终惑。
(2) 重啟Redis
? ~ cd /usr/local/redis-5.0.7
? redis-5.0.7 redis-server redis.conf
此時在控制臺中不會輸出日志。而是生成/usr/local/redis-5.0.7/logs.log
日志文件门扇。
-
Redis
配置參數(shù)(二)
序號 | 參數(shù) | 作用 |
---|---|---|
1 |
databases |
邏輯庫的數(shù)量雹有,默認16
|
2 |
save |
RDB 文件同步的頻率 |
3 |
rdbcompression |
同步RDB 文件的時候是否采用壓縮,默認yes
|
4 |
dbfilename |
rdb 鏡像文件名稱臼寄,默認dump.rdb
|
5 |
dir |
rdb 文件的目錄霸奕,默認./ ,為redis 目錄 |
6 |
requirepass |
訪問密碼吉拳,默認無需密碼 |
- 修改配置
(1) 修改配置文件
databases 4
save 900 1
save 300 10
save 60 10000
requirepass abc123456
(2) 重啟Redis
? ~ cd /usr/local/redis-5.0.7
? redis-5.0.7 redis-server redis.conf
(3) 使用RedisDesktopManager
客戶端連接
-
Redis
配置參數(shù)(三)
序號 | 參數(shù) | 作用 |
---|---|---|
1 |
maxclients |
最大連接數(shù)铅祸,默認無限制 |
2 |
maxmemory |
占用內(nèi)存的大小,默認無限制 |
3 |
appendonly |
開啟AOF 備份 |
4 |
appendfilename |
AOF 備份文件名 |
5 |
appendfsync |
AOF 同步的頻率合武,分為no 临梗、everysec 、always
|
注釋:appendfsync
值為no
表示系統(tǒng)決定同步頻率稼跳,everysec
表示每秒同步一次盟庞,always
表示每次修改數(shù)據(jù)都同步。
- 修改配置
(1) 修改配置文件
# save 900 1
# save 300 10
# save 60 10000
maxclients 2000
maxmemory 500m
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
開啟AOF
備份汤善,需要關閉RDB
備份什猖。
(2) 重啟Redis
? ~ cd /usr/local/redis-5.0.7
? redis-5.0.7 redis-server redis.conf
1.3 總結(jié)
- 技能清單
學些了NoSQL
數(shù)據(jù)庫的使用意義票彪。
掌握了Redis
數(shù)據(jù)庫的安裝方法。
掌握了Redis
客戶端的使用不狮。
了解了Redis
的常用配置降铸。
2. Redis常用數(shù)據(jù)結(jié)構(gòu)
2.1 介紹
-
Redis
的五種數(shù)據(jù)類型
無條件查詢記錄,字段的計算和字段的別名 -
Redis
的Key
命令
數(shù)據(jù)排序摇零、分頁推掸、去除重復記錄
2.2 Redis常用數(shù)據(jù)結(jié)構(gòu)
-
Redis
五種數(shù)據(jù)類型
字符串、哈希驻仅、列表谅畅、集合、有序集合 -
Redis
字符串類型
String
類型既可以保存普通文字噪服,也可以保存序列化的二進制數(shù)據(jù)毡泻。
String
類型最大可以存儲512M
數(shù)據(jù)。 - 字符串指令(一)
(1) 設置Key-Value
SET Key Value
(2) 獲取Value
GET Key
(3) 刪除Key-Value
DEL Key
命令行客戶端示例如下:
? ~ redis-cli -a "abc123456"
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> SET email drew@163.com
OK
127.0.0.1:6379> GET email
"drew@163.com"
127.0.0.1:6379> DEl email
(integer) 1
127.0.0.1:6379> GET email
(nil)
127.0.0.1:6379>
注釋:FLUSHDB
清空當前邏輯庫粘优、FLUSHALL
清空所有邏輯庫仇味。
- 字符串指令(二)
(1) 獲取截取Value
內(nèi)容
GETRANGE Key 起始位置 結(jié)束位置
(2) 獲取Value
長度
STRLEN Key
(3) 設置帶有過期時間(秒)的Key-Value
SETEX Key 時間數(shù)值 Value
Redis:0>set email drew@163.com
"OK"
Redis:0>getrange email 0 3
"drew"
Redis:0>getrange email 0 -1
"drew@163.com"
Redis:0>strlen email
"12"
Redis:0>setex username 5 drew
"OK"
Redis:0>get username
"drew"
Redis:0>get username
null
Redis:0>
- 字符串指令(三)
(1) 設置多個Key-Value
MSET Key1 Value1 Key2 Value2
(2) 獲取多個Value
MGET Key1 Key2
Redis:0>mset username jack sex male age 24
"OK"
Redis:0>mget username sex age
1) "jack"
2) "male"
3) "24"
- 字符串指令(四)
(1) 在Value
結(jié)尾追加內(nèi)容
APPEND Key 字符串
Redis:0>setex temp 60 ABCD
"OK"
Redis:0>get temp
"ABCD"
Redis:0>append temp 1234
"8"
Redis:0>get temp
"ABCD1234"
Redis:0>get temp
null
- 字符串指令(五)
(1)Value
自增1
INCR Key
(2)Value
自增指定的整數(shù)值
INCRBY Key 整數(shù)
(3)Value
自增指定的浮點數(shù)
INCRBYFLOAT Key 浮點數(shù)
(4)Value
自減1
DECR Key
(5)Value
自減指定的整數(shù)值
DECRBY Key 整數(shù)
Redis:0>setex num 100 0
"OK"
Redis:0>incr num
"1"
Redis:0>get num
"1"
Redis:0>incrby num 20
"21"
Redis:0>get num
"21"
Redis:0>incrby num -2
"19"
Redis:0>get num
"19"
Redis:0>incrbyfloat num 2.56
"21.56"
Redis:0>get num
"21.56"
Redis:0>incrbyfloat num -4.6
"16.96"
Redis:0>get num
"16.96"
注意:并沒有DECRBYFLOAT
自減指定的浮點數(shù)的方法。
-
Redis
哈希類型
哈希類型可以保存更復雜的結(jié)構(gòu)化數(shù)據(jù)雹顺。 - 哈希指令(一)
(1) 設置哈希表字段
HSET Key k v
(2) 設置哈希表多個字段
HMSET Key k v k v
(3) 獲取哈希表某個字段值
HGET Key k
(4) 獲取哈希表多個字段值
HMGET Key k1 k2 k3
(5) 獲取哈希表所有字段值
HGETALL Key
(6) 獲取哈希表中所有字段key
值
HKEYS Key
(7) 獲取哈希表中所有字段value
值
HVALS Key
(8) 獲取哈希表中字段數(shù)量
HLEN Key
(9) 判斷哈希表是否含有某個字段
HEXISTS Key k1
(10) 刪除哈希表的字段
HDEL Key k1 k2
Redis:0>hset 8000 ename Tom
"1"
Redis:0>hset 8000 job SELESMAN
"1"
Redis:0>hmset 9000 ename Scott job SALESMAN deptno 10
"OK"
Redis:0>hget 9000 ename
"Scott"
Redis:0>hmget 9000 ename deptno job
1) "Scott"
2) "10"
3) "SALESMAN"
Redis:0>hgetall 9000
1) "ename"
2) "Scott"
3) "job"
4) "SALESMAN"
5) "deptno"
6) "10"
Redis:0>hkeys 9000
1) "ename"
2) "job"
3) "deptno"
Redis:0>hvals 9000
1) "Scott"
2) "SALESMAN"
3) "10"
Redis:0>hlen 9000
"3"
Redis:0>hexists 9000 job
"1"
Redis:0> hdel 9000 job deptno
"2"
Redis:0>hkeys 9000
1) "ename"
- 哈希指令(二)
(1) 哈希表的某個字段加上指定的整數(shù)值
HINCRBY Key k num
(2) 哈希表的某個字段機上指定的浮點數(shù)
HINCRBYFLOAT Key k float
Redis:0>hmset 8000 deptno 10 sal 4000
"OK"
Redis:0>hincrby 8000 deptno 5
"15"
Redis:0>hincrbyfloat 8000 sal 500.5
"4500.5"
-
Redis
列表類型
列表類型可以保存序列化數(shù)據(jù)丹墨。
注釋:列表元素可以重復。 - 列表指令
(1) 右側(cè)插入元素
RPUSH Key 值1 值2 值3
(2) 左側(cè)插入元素
LPUSH Key 值1 值2
(3) 設置列表指定位置的值
LSET Key 位置 值
(4) 截取子列表
LRANGE Key 其實位置 結(jié)束位置
(5) 獲取列表長度
LLEN Key
(6) 獲取指定位置元素
LINDEX Key 位置
(7) 指定元素前/后插入元素
LINSERT Key before/after 指定元素 插入元素
(8) 刪除第一個元素
LPOP Key
(9) 刪除最后一個元素
RPOP Key
(10) 刪除指定元素
LREM Key 刪除數(shù)量(從左往右刪) 值
Redis:0>rpush dname 技術(shù)部 后勤部 售后部
"3"
Redis:0>lpush dname 秘書處
"4"
Redis:0>lset dname 2 銷售部
"OK"
Redis:0>lrange dname 0 2
1) "秘書處"
2) "技術(shù)部"
3) "銷售部"
Redis:0>lrange dname 0 -1
1) "秘書處"
2) "技術(shù)部"
3) "銷售部"
4) "售后部"
Redis:0>llen dname
"4"
Redis:0>lindex dname 2
"銷售部"
Redis:0>linsert dname before 秘書處 董事會
"5"
Redis:0>lrange dname 0 -1
1) "董事會"
2) "秘書處"
3) "技術(shù)部"
4) "銷售部"
5) "售后部"
Redis:0>lpop dname
"董事會"
Redis:0>rpop dname
"售后部"
Redis:0>lrange dname 0 -1
1) "秘書處"
2) "技術(shù)部"
3) "銷售部"
Redis:0>rpush dname 技術(shù)部
"4"
Redis:0>lpush dname 技術(shù)部
"5"
Redis:0>lrange dname 0 -1
1) "技術(shù)部"
2) "秘書處"
3) "技術(shù)部"
4) "銷售部"
5) "技術(shù)部"
Redis:0>lrem dname 2 技術(shù)部
"2"
Redis:0>lrange dname 0 -1
1) "秘書處"
2) "銷售部"
3) "技術(shù)部"
-
Redis
集合類型
可以將集合看做是元素不可以重復的列表无拗。
注釋:集合不可以重復带到、沒有索引、根據(jù)哈希值排序英染。 - 集合指令
(1) 集合添加元素
SADD Key item1 item2 item3
(2) 查看集合元素
SMEMBERS Key
(3) 獲取集合長度
SCARD Key
(4) 判斷是否含有某個元素
SISMEMBER Key item
(5) 刪除元素
SREM Key item1 item2
(6) 隨機刪除并返回集合的某個元素
SPOP Key
(7) 隨機返回集合中的元素
SRANDMEMBER Key 數(shù)量
Redis:0>sadd empno 8001 8002 8003 8002
"3"
Redis:0>smembers empno
1) "8001"
2) "8002"
3) "8003"
Redis:0>scard empno
"3"
Redis:0> sismember empno 8002
"1"
Redis:0> srem empno 8001
"1"
Redis:0>smembers empno
1) "8002"
2) "8003"
Redis:0> del empno
"1"
Redis:0> sadd empno 3 5 1 2 9
"5"
Redis:0>srandmember empno 3
1) "5"
2) "9"
3) "3"
Redis:0>spop empno
"2"
Redis:0>spop empno
"9"
Redis:0>smembers empno
1) "1"
2) "3"
3) "5"
-
Redis
有序集合類型
有序集合是帶有排序功能的集合(無重復值)揽惹,Redis
會按照元素分數(shù)值排序弯菊。 - 有序集合指令
(1) 添加元素
ZADD Key 分數(shù)值 元素 分數(shù)值 元素
(2) 提升元素的分數(shù)值
ZINCRBY Key 分數(shù)值 元素
(3) 獲取正序指定范圍元素
ZRANGE Key 起始序號 結(jié)束序號
(4) 獲取倒序指定范圍元素
ZREVRANGE Key 起始序號 結(jié)束序號
(5) 獲得有序集合長度
ZCARD Key
(6) 查詢某個分數(shù)值區(qū)間內(nèi)的元素數(shù)量
ZCOUNT Key 最小分數(shù)值 最大分數(shù)值
(7) 返回元素的分數(shù)值
ZSCORE Key 元素
(8) 獲取分數(shù)值區(qū)間內(nèi)的集合內(nèi)容(升序)
ZRANGEBYSCORE Key 最小分數(shù)值 最大分數(shù)值
其中谊却,(
表示開區(qū)間,+inf
表示正無窮递览,-inf
表示負無窮闪金。
(9) 獲取分數(shù)值區(qū)間內(nèi)的集合內(nèi)容(降序)
ZREVRANGEBYSCORE Key 最大分數(shù)值 最小分數(shù)值
(10) 獲取元素的升序排名(從0
開始)
ZRANK Key 元素
(11) 獲取元素的降序排名(從0
開始)
ZREVRANK Key 元素
(12) 刪除有序集合中的元素
ZREM Key 元素1 元素2
(13) 刪除排名區(qū)間內(nèi)的元素
ZREMRANGEBYRANK Key 最小排名 最大排名
(14) 刪除分數(shù)值區(qū)間內(nèi)的元素
ZREMRANGEBYSCORE Key 最小分數(shù)值 最大分數(shù)值
注意:字符串元素需要添加雙引號疯溺。-n
序號表示倒數(shù)第n
個。
Redis:0>zadd keyword 0 "鹿晗" 0 "馬云" 0 "張朝陽"
"3"
Redis:0>zrange keyword 0 1
1) "張朝陽"
2) "馬云"
Redis:0>zincrby keyword 1 "鹿晗"
"1"
Redis:0>zincrby keyword 5 "馬云"
"5"
Redis:0>zincrby keyword 2 "張朝陽"
"2"
Redis:0>zrevrange keyword 0 -1
1) "馬云"
2) "張朝陽"
3) "鹿晗"
Redis:0>zrange keyword 0 1
1) "鹿晗"
2) "張朝陽"
Redis:0>zcard keyword
"3"
Redis:0>zcount keyword 2 5
"2"
Redis:0>zscore keyword "馬云"
"5"
Redis:0>zrangebyscore keyword 2 5
1) "張朝陽"
2) "馬云"
Redis:0>zrangebyscore keyword 2 (5
1) "張朝陽"
Redis:0>zrangebyscore keyword 2 +inf
1) "張朝陽"
2) "馬云"
Redis:0>zrevrangebyscore keyword 5 2
1) "馬云"
2) "張朝陽"
Redis:0>zrank keyword "馬云"
"2"
Redis:0>zrevrank keyword "馬云"
"0"
Redis:0>zadd keyword 9 "李彥宏"
"1"
Redis:0>zrem keyword "鹿晗"
"1"
Redis:0>zrevrange keyword 0 -1
1) "李彥宏"
2) "馬云"
3) "張朝陽"
Redis:0>zremrangebyrank keyword 0 1
"2"
Redis:0>zremrangebyscore keyword 9 9
"1"
Redis:0>zrevrange keyword 0 -1
Redis:0>zadd keyword 2 "張朝陽" 7 "李彥宏" 10 "馬云"
"3"
Redis:0>zremrangebyrank keyword 0 -3
"1"
Redis:0>zrevrange keyword 0 -1
1) "馬云"
2) "李彥宏"
2.3 Redis中常用命令
-
Redis
命令參考
https://class.imooc.com/lesson/943#mid=22498 -
Redis
中的Key
命令
(1) 刪除記錄
DEL Key
(2) 判斷是否存在某個Key
EXISTS Key
(3) 設置過期時間(秒)
EXPIRE Key 秒值
(4) 設置過期時間(毫秒)
PEXPIRE Key 毫秒值
(5) 設置過期時間(UNIX
時間戳哎垦,單位為秒)
EXPIREAT Key UNIX秒值
(6) 設置過期時間(UNIX
時間戳囱嫩,單位為毫秒)
PEXPIREAT Key UNIX毫秒值
(7) 移除過期時間
PERSIST Key
(8) 把記錄遷移到其他邏輯庫
MOVE Key 新的邏輯庫
(9) 修改Key
名稱
RENAME OldKey NewKey
(10) 判斷值的數(shù)據(jù)類型
TYPE Key
Redis:0>set name drew
"OK"
Redis:0>exists name
"1"
Redis:0>del name
"1"
Redis:0>exists name
"0"
Redis:0>set name drew
"OK"
Redis:0>expire name 5
"1"
Redis:0>get name
null
Redis:0>expireat name 15790764623
"1"
Redis:0>move name 1
"1"
Redis:0>select 1
"OK"
Redis:1>get name
"drew"
Redis:1>rename name username
"OK"
Redis:1>get username
"drew"
Redis:1>sadd empno 8001 8002 8003 8002
"3"
Redis:1>type empno
"set"
2.4 總結(jié)
- 技能清單
學習了Redis
五種常用數(shù)據(jù)類型。
掌握了操作Key
的命令漏设。
3. Redis事務特性
3.1 介紹
-
Redis
事務機制
Redis
的事務機制的原理墨闲?
Redis
的事務具備具備ACID
屬性嗎?
Redis
的事務能用來做什么郑口? - 管理事務的命令
WATCH
鸳碧、UNWATCH
盾鳞、MULTI
、EXEC
瞻离、DISCARD
3.2 Redis事務特性
- 回顧
MySQL
數(shù)據(jù)庫事務機制
數(shù)據(jù)庫引入事務機制是為了防止對數(shù)據(jù)文件進行直接操作的時候出現(xiàn)意外宕機腾仅,引發(fā)數(shù)據(jù)錯亂。
undo
日志記錄了數(shù)據(jù)修改之前的原始狀態(tài)套利,redo
日志記錄了修改了哪些數(shù)據(jù)推励。
undo
日志和redo
日志保證了業(yè)務操作的原子性。 -
Redis
數(shù)據(jù)庫事務機制
Redis
是異步單線程執(zhí)行日裙,一個線程對應所有客戶端吹艇。哪個客戶端上傳了命令惰蜜,線程就會執(zhí)行昂拂,并不能保證一個客戶端的多個命令不會被其他客戶端的命令插隊。 -
Redis
事務的特點
Redis
的事務和數(shù)據(jù)庫的事務有明顯差異抛猖,它并不滿足數(shù)據(jù)庫事務的ACID
屬性格侯。Redis
的事務更像是批處理執(zhí)行。
序號 | 屬性 | Redis |
MySQL |
---|---|---|---|
1 |
原子性 | No |
Yes |
2 |
一致性 | Yes |
Yes |
3 |
隔離性 | Yes |
Yes |
4 |
持久性 | No |
Yes |
- 監(jiān)控記錄
為了保證事務的一致性财著,在開啟事務之前必須要使用WATCH
命令監(jiān)視要操作的記錄联四。
WATCH kill_num kill_user
- 開啟事務
MULTI
...
EXEC
開啟事務后所有操作都不會立即執(zhí)行,只有執(zhí)行EXEC
命令的時候才會批處理執(zhí)行撑教。如果我們監(jiān)視的數(shù)據(jù)被其他客戶端修改了朝墩,那么我們開啟的事務就會自動關閉。
- 開啟事務后所有操作都不會立即執(zhí)行伟姐,只有執(zhí)行
EXEC
命令的時候才會批處理執(zhí)行收苏。
控制臺1
Redis:0>set num 0
"OK"
Redis:0>watch num
"OK"
Redis:0>multi
"OK"
Redis:0>incr num
"QUEUED"
Redis:0>incrby num 10
"QUEUED"
控制臺2
Redis:0>get num
"0"
控制臺1
Redis:0>exec
1) "1"
2) "11"
控制臺2
Redis:0>get num
"11"
- 如果我們監(jiān)視的數(shù)據(jù)被其他客戶端修改了,那么我們開啟的事務就會自動關閉愤兵。
控制臺1
Redis:0>set num 0
"OK"
Redis:0>watch num
"OK"
Redis:0>multi
"OK"
Redis:0>incrby num 500
"QUEUED"
控制臺2
Redis:0>set num 50
"OK"
Redis:0>
控制臺1
Redis:0>exec
Redis:0>get num
"50"
- 取消事務
Redis
沒有事務的回滾機制鹿霸,并不能保證原子性。
事務在沒有提交執(zhí)行(EXEC
)前秆乳,是可以取消的懦鼠。如果事務已經(jīng)提交執(zhí)行(EXEC
),就無法取消了屹堰。
DISCARD
Redis:0>set num 0
"OK"
Redis:0>watch num
"OK"
Redis:0>multi
"OK"
Redis:0>set num 100
"QUEUED"
Redis:0>discard
"OK"
Redis:0>exec
"ERR EXEC without MULTI"
Redis:0>get num
"0"
3.3 總結(jié)
- 技能清單
學習了Redis
事務機制的原理
掌握管理Redis
事務的命令
4. Redis與Python交互
4.1 介紹
- 安裝
redis-py
模塊
升級pip
命令肛冶,用pip
命令安裝redis-py
模塊 - 掌握
Redis
的CRUD
操作
用redis-py
模塊管理redis
中的數(shù)據(jù),包括事務機制扯键。 - 編寫程序案例
利用Python
多線程睦袖,模擬電商秒殺活動的商品搶購,用Redis
事務來避免超買和超賣忧陪。
4.2 Redis與Python的交互
1.redis-py
模塊安裝
? ~ pip3 install redis
-
redis-py
創(chuàng)建連接
import redis
try:
r = redis.Redis(
host="localhost",
port=6379,
password="abc123456",
db=0
)
except Exception as e:
print(e)
注意: 與MySQL
不同扣泊,Redis
沒有用戶管理近范。
-
redis-py
創(chuàng)建連接池
import redis
try:
pool = redis.ConnectionPool(
host="localhost",
port=6379,
password="abc123456",
db=0,
max_connections=200
)
except Exception as e:
print(e)
-
redis-py
創(chuàng)建與關閉連接
從連接池中獲得的連接,不用關閉延蟹,垃圾回收的時候連接會自動被歸還到連接池评矩。
# 連接池文件代碼
import redis
try:
pool = redis.ConnectionPool(
host="localhost",
port=6379,
password="abc123456",
db=0,
max_connections=200
)
except Exception as e:
print(e)
# 連接文件代碼
import redis
from test.redis_db import pool
con = redis.Redis(
connection_pool=pool
)
# ...
del con
-
redis-py
字符串指令(一)
設置單個Key
-Value
import time
import redis
from test.redis_db import pool
con = redis.Redis(
connection_pool=pool
)
try:
con.set("country", "英國")
con.set("city", "倫敦")
city = con.get("city").decode("utf-8") # 倫敦
print(city) # 倫敦
con.expire("city", 5)
time.sleep(6)
city = con.get("city")
print(city) # None
except Exception as e:
print(e)
finally:
del con
注意:中文需要使用decode("utf-8")
解碼。
-
redis-py
字符串指令(二)
設置多個Key
-Value
import redis
from test.redis_db import pool
con = redis.Redis(
connection_pool=pool
)
try:
con.delete("country", "city")
con.mset({"country": "德國", "city": "柏林"})
result=con.mget("country", "city")
print(result) # [b'\xe5\xbe\xb7\xe5\x9b\xbd', b'\xe6\x9f\x8f\xe6\x9e\x97']
for one in result:
print(one.decode("utf-8")) # 德國 柏林
except Exception as e:
print(e)
finally:
del con
注釋:刪除redis
字段con.delete("key1", "key2")
阱飘。
-
redis-py
列表指令
from test.redis_db import pool
import redis
con = redis.Redis(
connection_pool=pool
)
try:
con.rpush('dname', '董事會', '秘書處', '財務部', '技術(shù)部')
con.lpop('dname')
result = con.lrange('dname', 0, -1)
for item in result:
print(item.decode('utf-8'))
except Exception as e:
print(e) # 秘書處 財務部 技術(shù)部
finally:
del con
-
redis-py
集合指令
from test.redis_db import pool
import redis
con = redis.Redis(
connection_pool=pool
)
try:
con.sadd('employee', 8001, 8002, 8003)
con.srem('employee', 8002)
result = con.smembers('employee')
for one in result:
print(one.decode('utf-8')) # 8001 8003
con.lpush("code", "Java", "PHP", "HTML", "Python")
con.rpop("code")
result = con.lrange("code", "0", "-1")
for one in result:
print(one.decode('utf-8')) # Python HTML PHP
except Exception as e:
print(e)
finally:
del con
-
redis-py
有序集合指令
from test.redis_db import pool
import redis
con = redis.Redis(
connection_pool=pool
)
try:
con.zadd('keyword', {'馬云': 0, '張朝陽': 0, "丁磊": 0})
con.zincrby('keyword', 10, '馬云')
result = con.zrevrange('keyword', 0, -1)
for one in result:
print(one.decode('utf-8')) # 馬云 張朝陽 丁磊
except Exception as e:
print(e)
finally:
del con
-
redis-py
哈希指令
from test.redis_db import pool
import redis
con = redis.Redis(
connection_pool=pool
)
try:
con.hmset('9527', {'name': 'Scott', 'sex': 'male', 'age': 35})
con.hset('9527', 'city', '紐約')
con.hdel('9527', 'sex')
result = con.hexists('9527', 'name')
print(result) # True
result = con.hgetall('9527')
for key in result:
print(key.decode('utf-8'), result.get(key).decode('utf-8'))
# name Scott
# age 35
# city 紐約
except Exception as e:
print(e)
finally:
del con
-
redis-py
的事務函數(shù)
redis-py
模塊用pipeline
(管道)的方式向Redis
服務器傳遞批處理命令和執(zhí)行事務斥杜。
from test.redis_db import pool
import redis
con = redis.Redis(
connection_pool=pool
)
try:
pipeline = con.pipeline()
pipeline.watch('9527') # 監(jiān)視數(shù)據(jù)
pipeline.multi() # 開啟事務
pipeline.hset('9527', 'name', 'Jack')
pipeline.hset('9527', 'age', 23)
pipeline.execute() # 提交事務
except Exception as e:
print(e)
finally:
if 'pipeline' in dir():
pipeline.reset() # 只有重置pipeline,con對應的連接才會從連接池回收
del con
- 從
txt
文檔中解析學生的信息沥匈,把語數(shù)外成績都超過85
分的學生信息蔗喂,緩存到Redis
哈希表中。
620,王偉,2-1,96,89,75
621,趙芳芳,2-1,71,62,80
622,許麗麗,2-2,96,88,89
624,胡倩倩,2-2,98,99,100
625,李偉,2-3,53,68,67
from test.redis_db import pool
import redis
con = redis.Redis(
connection_pool=pool
)
try:
file = open(
file="考試成績.txt",
mode='r',
encoding='utf-8'
)
data = file.read().splitlines()
for item in data:
temp = item.split(',')
sid = temp[0]
name = temp[1]
class_no = temp[2]
score_1 = int(temp[3])
score_2 = int(temp[4])
score_3 = int(temp[5])
if score_1 >= 85 and score_2 >= 85 and score_3 >= 85:
con.hmset(sid, {
'name': name,
'class_no': class_no,
'score_1': score_1,
'score_2': score_2,
'score_3': score_3
})
except Exception as e:
print(e)
finally:
if 'file' in dir():
file.close()
del con
- 用
Python
程序模擬300
名觀眾高帖,為五位嘉賓(馬云缰儿、丁磊、張朝陽散址、馬化騰乖阵、李彥宏)隨機投票,最后按照降序排列結(jié)果预麸。
import random
from test.redis_db import pool
import redis
con = redis.Redis(
connection_pool=pool
)
try:
con.delete('ballot')
con.zadd('ballot', {'馬云': 0, '丁磊': 0, '張朝陽': 0, '馬化騰': 0, '李彥宏': 0})
names = ['馬云', '丁磊', '張朝陽', '馬化騰', '李彥宏']
for i in range(0, 300):
num = random.randint(0, 4)
name = names[num]
con.zincrby('ballot', 1, name)
result = con.zrevrange('ballot', 0, -1, "WITHSCORES") # 加上WITHSCORES瞪浸,表示獲得值和分數(shù)
for item in result:
print(item[0].decode('utf-8'), int(item[1]))
except Exception as e:
print(e)
finally:
del con
-
Python
線程池
如果程序中經(jīng)常需要使用線程,頻繁的創(chuàng)建和銷毀線程會浪費很多硬件資源吏祸,所以需要把線程與任務分離開对蒲。線程池中的線程可以反復利用,省去了重復創(chuàng)建的麻煩贡翘。
import time
from concurrent.futures.thread import ThreadPoolExecutor
def say_hello():
time.sleep(1)
print('Hello')
executor = ThreadPoolExecutor(20)
for i in range(0, 10):
executor.submit(say_hello)
- 用
Python
多線程模擬商品秒殺過程蹈矮,不可以出現(xiàn)超買和超賣的情況。假設A
商品有10
件參與秒殺活動床估,1000
個用戶參與秒殺含滴,10
分鐘秒殺自動結(jié)束。
from test.redis_db import pool
import redis
import random
from concurrent.futures.thread import ThreadPoolExecutor
# 生成1000個用戶id
s = set()
while True:
if len(s) == 1000:
break
num = random.randint(10000, 100000)
s.add(num)
# 創(chuàng)建連接
con = redis.Redis(
connection_pool=pool
)
try:
# 刪除相關數(shù)據(jù)
con.delete('kill_total', 'kill_num', 'kill_flag', 'kill_user')
# 初始化數(shù)據(jù)
con.set('kill_total', 10) # 一共10件秒殺商品
con.set('kill_num', 0) # 已秒殺幾件商品
con.set('kill_flag', 1) # 秒殺是否結(jié)束
con.expire('kill_flag', 60 * 10) # 10分鐘后描述結(jié)束
except Exception as e:
print(e)
finally:
del con
# 創(chuàng)建線程池
executor = ThreadPoolExecutor(200)
'''
kill_total 商品總數(shù)
kill_num 成功搶購數(shù)
kill_flag 有效標志位
kill_user 成功搶購的用戶ID
'''
def buy():
connection = redis.Redis(
connection_pool=pool
)
try:
if connection.exists('kill_flag') == 1:
pipeline = connection.pipeline()
pipeline.watch('kill_num', 'kill_user')
total = int(pipeline.get('kill_total').decode('utf-8'))
num = int(pipeline.get('kill_num').decode('utf-8'))
if num < total:
pipeline.multi()
pipeline.incr('kill_num') # 已秒殺商品數(shù)加1
user_id = s.pop()
pipeline.rpush('kill_user', user_id) # 保存秒殺到商品的用戶id
pipeline.execute()
except Exception as e:
print(e)
finally:
if 'pipeline' in dir():
pipeline.reset()
del con
for i in range(0, 1000):
executor.submit(buy)
print('秒殺已經(jīng)結(jié)束')
4.3 總結(jié)
- 技能清單
掌握了redis-py
模塊的連接池
掌握了redis-py
模塊的CRUD
操作
掌握了redis-py
模塊的事務管理
5. 開發(fā)新聞管理系統(tǒng)
- 代碼地址
https://github.com/nmwei/database-vega - 技能清單
完成了已審批新聞的緩存
完成了刪除新聞丐巫,自動刪除redis
緩存的功能
完成了編輯新聞谈况,自動刪除redis
緩存的功能