目录
一、发布订阅
1.1、常用命令
1.2、示例演示
二、事务管理
2.1 Multi、Exec、Discard
2.2 示例演示
2.3 事务的错误处理
2.4 事务的冲突问题
2.4.1 事务场景
2.4.2 悲观锁
2.4.3 乐观锁
2.4.4 事务解决冲突—WATCH
2.4.5 UNWATCH
2.4.6 Redis事务的三个特性
Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。Redis 客户端可以订阅任意数量的频道。下图展示了频道 channel1 ,以及订阅这个频道的三个客户端 —— client1 、client2 和 client3 之间的关系:
当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:
序号 | 命令语法 | 描述 |
---|---|---|
1 | PSUBSCRIBE pattern [pattern ...] | 订阅一个或多个符合给定模式的频道 |
2 | PUBSUB subcommand [argument [argument ...]] | 查看订阅与发布系统的状态 |
3 | PUBLISH channel message | 将信息发送到指定的频道 |
4 | PUNSUBSCRIBE [pattern [pattern ...]] | 退订所有给定模式的频道 |
5 | SUBSCRIBE channel [channel ...] | 订阅给定的一个或多个频道的信息 |
6 | UNSUBSCRIBE [channel [channel ...]] | 退订给定的频道 |
创建四个客户端Client1------Client 4 :
#cli1 创建订阅的频道redisChat
127.0.0.1:6379> SUBSCRIBE redisChat
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisChat"
3) (integer) 1
#cli2 在同一频道redisChat 发布消息
127.0.0.1:6379> PUBLISH redisChat "SendMessage_1"
(integer) 1
#此处可切换到 cli1内查看是否读取到cli2发布的消息
#cli3 在同一频道redisChat 发布消息
127.0.0.1:6379> PUBLISH redisChat "SendMessage_2"
(integer) 1
#此处可切换到 cli1内查看是否读取到cli3发布的消息
#cli4 创建订阅的频道redisChat
127.0.0.1:6379> SUBSCRIBE redisChat
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisChat"
3) (integer) 1
#cli3 在同一频道redisChat 发布消息
127.0.0.1:6379> PUBLISH redisChat "SendMessage_2"
(integer) 1
#此处可切换到 cli1及cli4内查看是否读取到cli3发布的消息
cli1收到3条信息 分别来自于 cli2一次 以及 cli3两次
cli4收到1条信息 cli3一次
Redis 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。Redis 事务的主要作用就是串联多个命令防止别的命令插队。
从输入Multi命令开始、后面输入的操作命令都会依次进入到命令队列当中,但不会执行。直到输入Exec后、Redis会将之前的命令队列中的命令依次执行。
组队过程中,可以通过discard来放弃组队:
1、Redis的事务可以一次执行多条命令:
2、批量操作在发送Exec命令前被放入队列缓存;
3、收到Exec命令后,进入事务执行,如果事务中有任意命令执行失败,其余的命令依旧会执行;
4、在事务的执行过程中,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求,不会插入到事务执行的命令序列中.
#组队阶段成功、提交成功的情况
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)> exec
(1) OK
(2) OK
#组队阶段报错、提交必然报错(所有数据全部回滚)
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> set k4
(error) ERR wrong number of arguments for 'set' command
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> multi
OK
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> incr k3
QUEUED
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> get k3
QUEUED
127.0.0.1:6379(TX)> exec
(1) OK
(2) (error) ERR value is not an integer or out of range
(3) OK
(4) "v3"
组队时某个命令出现了错误报告,执行时整个的队列都会被取消:
执行时某个命令报了错误,则只有报错的命令不会被执行,而其他命令都会执行,不会回滚:
有一账户余额10000元,现在出现三个请求,第一个请求想给金额-8000元,第二个请求想给金额-5000元,第三个请求想给金额-1000元。
如果没有事务管理,则有可能出现如下场景:
悲观锁(Pessimistic Lock)顾名思义,就是很悲观。每次去拿数据时都认为别人会修改,所以在每次拿数据时都会上锁,这样别人想拿到这个数据就会停顿,直到它拿到锁为止。在传统的关系型数据库内就会用到这种锁机制,比如 行锁 表锁 读锁 写锁,都是在操作之前先进行上锁处理。
乐观锁(Optimistic Lock)顾名思义,就是很乐观。每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。
在执行multi之前,先执行 watch key1 [key2 ....] 用于指定key的监视,如果在事务执行前这些key被其他命令锁改动,那么事务将被打断
#cli1
set money 10000
#cli2
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 8000
QUEUED
#cli3
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby money 3000
QUEUED
#cli2
exec
#cli3
exec
用于取消命令对所有key的监视,如果在执行watch命令之后,Exec或DisCard命令先被执行的话,那么就不需要再次执行unwatch。
1、单独的隔离操作
事务中所有命令都会序列化,按顺序执行。事务在执行过程中,不会被其他客户端发来的请求锁打断。
2、没有隔离级别的概念
队列中的命令没有提交前都不会被实际执行,因为事务提交前,所有指令都是处于等待状态。
3、不保证原子性
事务中如果有一条命令执行失败,其后命令依旧会执行,并不会回滚。