目录
【Redis事务】
Redis支持简单的事务,redis事务支持比较弱,只能保证事务中的每个操作连续执行。
Redis 提供了 MULTI、EXEC 两个命令来完成事务。Redis 中并没有提供回滚机制。虽然 Redis 提供了 DISCARD 命令,但是,这个命 令只能用来主动放弃事务执行,把暂存的命令队列清空,起不到回滚的效果。
1. multi , 告诉Redis服务器开启一个事务。注意,只是开启,而不是执行。之后的所有命令都是在排队中。
2. exec , 告诉Redis开始执行事务,上面的命令开始依次执行。
3. discard,告诉Redis取消事务,上面的命令取消。
4. watch ,监视某一个键值对,它的作用是在事务执行之前如果监视的键值被修改,事务会被取消
127.0.0.1:6379> MSET zhangsan 100 lisi 200 //张三100元,李四200元
OK
127.0.0.1:6379> MULTI //开启事务
OK
127.0.0.1:6379(TX)> DECRBY zhangsan 10 //张三减10元
QUEUED
127.0.0.1:6379(TX)> INCRBY lisi 10 //李四加10元
QUEUED
127.0.0.1:6379(TX)> EXEC //提交事务
1) (integer) 90
2) (integer) 210
127.0.0.1:6379> MGET zhangsan lisi
1) "90"
2) "210"
MySQL和Redis操作事务的对比:
1.事务提交前,先检查命令语法是否正确
2.提交后的命令, 一定会执行
3.有命令报错,也会执行完
4.不能回滚
5.和批量操作的区别:redis事务执行exec时,命令要么执行, 要么都不执行;批量操作不会检查语法。
MySQL | Redis | |
开启 | start transaction | muitl |
语句 | 普通sql | 普通命令 |
失败 | rollback 回滚 | discard 取消 |
成功 | commit | exec |
MySQL中的事务:
Redis中的事务处理:
[案例1] wang有200元,zhao有700元,zhao给wang转账100元,用Redis事务处理。
[案例2] 给zhao 减了100,然后执行一个错误的命令,再执行exec就不会成功了。
[案例3] 事务队列后不执行,而是discard取消。
假设,我正在买票:Ticket -1 , money -100,而票只有1张, 如果在我multi之后,和exec之前, 票被别人买了,即ticket变成0了。这种情况会发生什么?
两个终端,分别模拟两个人lisi 和 wang ,都有300块钱,都来买仅剩下的1张票(票100元1张):
我该如何观察这种情景,并不再提交?
悲观的想法: 世界充满危险,肯定有人和我抢, 给 ticket上锁, 只有我能操作. [悲观锁]
乐观的想法:没有那么人和我抢,因此,我只需要注意,有没有人更改ticket的值就可以了 [乐观锁]
Redis的事务中,启用的是乐观锁,只负责监测key没有被改动. 具体的命令:watch命令(监视)
还是上面的案例,重新再来,只是事务开始之前先 watch ticket:
watch key1 key2 ... keyN 作用:监听key1 key2..keyN有没有变化,如果有变, 则事务取消
unwatch 作用: 取消所有watch监听
再来看看三种情况的redis事务的处理情况:
# 正式情况的事务
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name zhangsan
QUEUED
127.0.0.1:6379> get name
QUEUED
127.0.0.1:6379> exec
1) OK
2) "zhangsan"
# 事务中出现语法错误
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set date 20230428
QUEUED
127.0.0.1:6379> hahaha //输入不存在的命令,没有返回QUEUED,直接报错
(error) ERR unknown command `hahaha`, with args beginning with:
127.0.0.1:6379> exec //此时上面的两条命令都不会执行
(error) EXECABORT Transaction discarded because of previous errors.
# 事务中出现命令类型用法错误
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set date 20230428 //设置一个字符串类型
QUEUED
127.0.0.1:6379> hgetall date //使用哈希的命令获取
QUEUED
127.0.0.1:6379> get date //再使用字符串的命令获取
QUEUED
127.0.0.1:6379> exec //此时第二条报异常信息,但是不影响后面的执行
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) "20230428"
【Redis消息订阅】
SUBSCRIBE channel [channel ...] 订阅给定的一个或多个频道的信息。
UNSUBSCRIBE [channel [channel ...]] 指示客户端退订给定的频道。
PUNSUBSCRIBE [pattern [pattern ...]] 指示客户端退订所有给定模式。
订阅端: Subscribe 频道名称
发布端: publish 频道名称 发布内容
[测试案例] 打开三个终端,1个用来发布消息,另外两个接收消息。
先在接收端使用 Subscribe:
然后在发布端使用publish:
此时接收端:
发布端:
接收端:
psubscribe 通配符匹配接收:
接收端:
发布端:
接收端: