Redis事务/Redis 发布订阅

目录

理论

Redis事务的概念:

Redis事务没有隔离级别的概念:

Redis不保证原子性:

Redis事务的三个阶段:

Redis事务相关命令:

实践

悲观锁:

乐观锁:

Redis 发布订阅


理论

Redis事务的概念:

Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列
化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事
务执行命令序列中。
总结说: redis 事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。

Redis事务没有隔离级别的概念:

批量操作在发送 EXEC 命令前被放入队列缓存,并不会被实际执行!

Redis不保证原子性:

Redis 中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其
余的命令仍会被执行。

Redis事务的三个阶段:

  • 开始事务
  • 命令入队
  • 执行事务

Redis事务相关命令:

watch key1 key2 ... # 监视一或多个 key, 如果在事务执行之前,被监视的 key 被其他命令改动,则事务被打断 ( 类似乐观锁 )
multi # 标记一个事务块的开始(queued
exec # 执行所有事务块的命令 (一旦执行 exec 后,之前加的监控锁都会被取消掉 )
discard # 取消事务,放弃事务块中的所有命令
unwatch # 取消 watch 对所有 key 的监控

实践

正常执行

Redis事务/Redis 发布订阅_第1张图片

 放弃事务

Redis事务/Redis 发布订阅_第2张图片

 若在事务队列中存在命令性错误(类似于java编译性错误),则执行EXEC命令时,所有命令都不会执行

Redis事务/Redis 发布订阅_第3张图片

 若在事务队列中存在语法性错误(类似于java1/0的运行时异常),则执行EXEC命令时,其他正确命令会被执行,错误命令抛出异常。

Redis事务/Redis 发布订阅_第4张图片

Watch 监控

悲观锁:

悲观锁 (Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿到这个数据就会 block 直到它拿到锁。传统的关系型数据库里面就 用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在操作之前先上锁。

乐观锁:

乐观锁 (Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会 上锁。但是在更新的时候会判断一下再此期间别人有没有去更新这个数据,可以使用版本号等机制,乐 观锁适用于多读的应用类型,这样可以提高吞吐量,乐观锁策略:提交版本必须大于记录当前版本才能 执行更新。
测试:
1 、初始化信用卡可用余额和欠额
127 .0.0.1:6379> set balance 100
OK
127 .0.0.1:6379> set debt 0
OK
2 、使用 watch 检测 balance ,事务期间 balance 数据未变动,事务执行成功
127 .0.0.1:6379> watch balance
OK
127 .0.0.1:6379> MULTI
OK
127 .0.0.1:6379> decrby balance 20
QUEUED
127 .0.0.1:6379> incrby debt 20
QUEUED
127 .0.0.1:6379> exec
1 ) (integer) 80
2 ) (integer) 20
3 、使用 watch 检测 balance ,事务期间 balance 数据变动,事务执行失败!
# 窗口一
127 .0.0.1:6379> watch balance
OK
127 .0.0.1:6379> MULTI # 执行完毕后,执行窗口二代码测试
OK
127 .0.0.1:6379> decrby balance 20
QUEUED
127 .0.0.1:6379> incrby debt 20
QUEUED
127 .0.0.1:6379> exec # 修改失败!
(nil)
# 窗口二
127 .0.0.1:6379> get balance
"80"
127 .0.0.1:6379> set balance 200
OK
# 窗口一:出现问题后放弃监视,然后重来!
127 .0.0.1:6379> UNWATCH # 放弃监视
OK
127 .0.0.1:6379> watch balance
OK
127 .0.0.1:6379> MULTI
OK
127 .0.0.1:6379> decrby balance 20
QUEUED
127 .0.0.1:6379> incrby debt 20
QUEUED
127 .0.0.1:6379> exec # 成功!
1 ) (integer) 180
2 ) (integer) 40
说明:
一但执行 EXEC 开启事务的执行后,无论事务使用执行成功, WARCH 对变量的监控都将被取消。故当事务执行失败后,需重新执行 WATCH 命令对变量进行监控,并开启新的事务进行操作。
小结
watch 指令类似于乐观锁,在事务提交时,如果 watch 监控的多个 KEY 中任何 KEY 的值已经被其他客户端更改,则使用 EXEC 执行事务时,事务队列将不会被执行,同时返回 Nullmulti-bulk 应答以通知调用者事 务执行失败。

Redis 发布订阅

是什么
Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。
Redis 客户端可以订阅任意数量的频道。
订阅 / 发布消息图:

Redis事务/Redis 发布订阅_第5张图片

下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 client5 client1 之间的关系:

Redis事务/Redis 发布订阅_第6张图片

 当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

Redis事务/Redis 发布订阅_第7张图片

命令
这些命令被广泛用于构建即时通信应用,比如网络聊天室 (chatroom) 和实时广播、实时提醒等。

Redis事务/Redis 发布订阅_第8张图片

测试
以下实例演示了发布订阅是如何工作的。在我们实例中我们创建了订阅频道名为 redisChat :
redis 127 .0.0.1:6379> SUBSCRIBE redisChat
Reading messages... (press Ctrl-C to quit)
1 ) "subscribe"
2 ) "redisChat"
3 ) (integer) 1
现在,我们先重新开启个 redis 客户端,然后在同一个频道 redisChat 发布两次消息,订阅者就能接收到消息。
redis 127 .0.0.1:6379> PUBLISH redisChat "Hello,Redis"
(integer) 1
redis 127 .0.0.1:6379> PUBLISH redisChat "Hello Kuangshen"
(integer) 1
# 订阅者的客户端会显示如下消息
1 ) "message"
2 ) "redisChat"
3 ) "Hello,Redis"
1 ) "message"
2 ) "redisChat"
3 ) "Hello Kuangshen"
原理
Redis 是使用 C 实现的,通过分析 Redis 源码里的 pubsub.c 文件,了解发布和订阅机制的底层实现,籍此加深对 Redis 的理解。
Redis 通过 PUBLISH SUBSCRIBE PSUBSCRIBE 等命令实现发布和订阅功能。
通过 SUBSCRIBE 命令订阅某频道后, redis-server 里维护了一个字典,字典的键就是一个个 channel,而字典的值则是一个链表,链表中保存了所有订阅这个 channel 的客户端。 SUBSCRIBE 命令的关 键,就是将客户端添加到给定 channel 的订阅链表中。
通过 PUBLISH 命令向订阅者发送消息, redis-server 会使用给定的频道作为键,在它所维护的 channel字典中查找记录了订阅这个频道的所有客户端的链表,遍历这个链表,将消息发布给所有订阅者。
Pub/Sub 从字面上理解就是发布( Publish )与订阅( Subscribe ),在 Redis 中,你可以设定对某一个 key 值进行消息发布及消息订阅,当一个 key 值上进行了消息发布后,所有订阅它的客户端都会收到相应 的消息。这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊等功能。
使用场景
Pub/Sub 构建实时消息系统
Redis Pub/Sub 系统可以构建实时的消息系统
比如很多用 Pub/Sub 构建的实时聊天系统的例子。

你可能感兴趣的:(Redis,redis,缓存,数据库)