理论
Redis事务的概念:
Redis
事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列
化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事
务执行命令序列中。
总结说:
redis
事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。
Redis事务没有隔离级别的概念:
批量操作在发送
EXEC
命令前被放入队列缓存,并不会被实际执行!
Redis不保证原子性:
Redis
中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其
余的命令仍会被执行。
Redis事务的三个阶段:
- 开始事务
- 命令入队
- 执行事务
Redis事务相关命令:
watch key1 key2 ... # 监视一或多个 key, 如果在事务执行之前,被监视的 key 被其他命令改动,则事务被打断 ( 类似乐观锁 )multi # 标记一个事务块的开始(queued )exec # 执行所有事务块的命令 (一旦执行 exec 后,之前加的监控锁都会被取消掉 )discard # 取消事务,放弃事务块中的所有命令unwatch # 取消 watch 对所有 key 的监控
实践
正常执行
放弃事务
若在事务队列中存在命令性错误(类似于java编译性错误),则执行EXEC命令时,所有命令都不会执行
若在事务队列中存在语法性错误(类似于java的1/0的运行时异常),则执行EXEC命令时,其他正确命令会被执行,错误命令抛出异常。
Watch 监控
悲观锁:
悲观锁
(Pessimistic Lock),
顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿到这个数据就会
block
直到它拿到锁。传统的关系型数据库里面就
用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在操作之前先上锁。
乐观锁:
乐观锁
(Optimistic Lock),
顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会
上锁。但是在更新的时候会判断一下再此期间别人有没有去更新这个数据,可以使用版本号等机制,乐
观锁适用于多读的应用类型,这样可以提高吞吐量,乐观锁策略:提交版本必须大于记录当前版本才能
执行更新。
测试:
1
、初始化信用卡可用余额和欠额
127 .0.0.1:6379> set balance 100OK127 .0.0.1:6379> set debt 0OK
2
、使用
watch
检测
balance
,事务期间
balance
数据未变动,事务执行成功
127 .0.0.1:6379> watch balanceOK127 .0.0.1:6379> MULTIOK127 .0.0.1:6379> decrby balance 20QUEUED127 .0.0.1:6379> incrby debt 20QUEUED127 .0.0.1:6379> exec1 ) (integer) 802 ) (integer) 20
3
、使用
watch
检测
balance
,事务期间
balance
数据变动,事务执行失败!
# 窗口一127 .0.0.1:6379> watch balanceOK127 .0.0.1:6379> MULTI # 执行完毕后,执行窗口二代码测试OK127 .0.0.1:6379> decrby balance 20QUEUED127 .0.0.1:6379> incrby debt 20QUEUED127 .0.0.1:6379> exec # 修改失败!(nil)# 窗口二127 .0.0.1:6379> get balance"80"127 .0.0.1:6379> set balance 200OK# 窗口一:出现问题后放弃监视,然后重来!127 .0.0.1:6379> UNWATCH # 放弃监视OK127 .0.0.1:6379> watch balanceOK127 .0.0.1:6379> MULTIOK127 .0.0.1:6379> decrby balance 20QUEUED127 .0.0.1:6379> incrby debt 20QUEUED127 .0.0.1:6379> exec # 成功!1 ) (integer) 1802 ) (integer) 40
说明:
一但执行
EXEC
开启事务的执行后,无论事务使用执行成功,
WARCH
对变量的监控都将被取消。故当事务执行失败后,需重新执行
WATCH
命令对变量进行监控,并开启新的事务进行操作。
小结
watch
指令类似于乐观锁,在事务提交时,如果
watch
监控的多个
KEY
中任何
KEY
的值已经被其他客户端更改,则使用
EXEC
执行事务时,事务队列将不会被执行,同时返回
Nullmulti-bulk
应答以通知调用者事
务执行失败。
Redis 发布订阅
是什么
Redis
发布订阅
(pub/sub)
是一种消息通信模式:发送者
(pub)
发送消息,订阅者
(sub)
接收消息。
Redis
客户端可以订阅任意数量的频道。
订阅
/
发布消息图:
下图展示了频道
channel1
, 以及订阅这个频道的三个客户端
—— client2
、
client5
和
client1
之间的关系:
当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:
命令
这些命令被广泛用于构建即时通信应用,比如网络聊天室
(chatroom)
和实时广播、实时提醒等。
测试
以下实例演示了发布订阅是如何工作的。在我们实例中我们创建了订阅频道名为
redisChat
:
redis 127 .0.0.1:6379> SUBSCRIBE redisChatReading 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) 1redis 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
构建的实时聊天系统的例子。