Redis事务

Redis事务
Redis事务中文文档

为什么要用事务?

Redis 的单个命令是原子性的(比如 get set mget mset),如果涉及到多个命令的时候,需要把多个命令作为一个不可分割的处理序列,就需要用到事务

例如:我们之前说的用 setnx 实现分布式锁,我们先 set,然后设置对 key 设置 expire,防止 del 发生异常的时候锁不会被释放,业务处理完了以后再 del,这三个动作我们就希望它们作为一组命令执行。

Redis 的事务有两个特点
1、按进入队列的顺序执行
2、不会受到其他客户端的请求的影响

Redis 的事务涉及到四个命令

multi(开启事务),exec(执行事务),discard(取消事务),watch(监视)

 

事务的用法

案例场景:

vincent 和 lily 各有 1000 元,vincent 需要向 lily 转账 100 元
vincent 的账户余额减少 100 元,lily 的账户余额增加 100 元

127.0.0.1:6379> set vincent 1000
OK

127.0.0.1:6379> set lily 1000
OK

127.0.0.1:6379> multi
OK

127.0.0.1:6379> decrby vincent 100
QUEUED

127.0.0.1:6379> incrby lily 100
QUEUED

127.0.0.1:6379> exec
1) (integer) 900
2) (integer) 1100

127.0.0.1:6379> get vincent
"900"

127.0.0.1:6379> get lily
"1100"

解释:

  • 通过 multi 的命令开启事务。事务不能嵌套,多个 multi 命令效果一样
  • multi 执行后,客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中, 当 exec 命令被调用时, 所有队列中的命令才会被执行
  • 通过 exec 的命令执行事务。如果没有执行 exec,所有的命令都不会被执行

如果中途不想执行事务了,怎么办?
可以调用 discard 可以清空事务队列,放弃执行。

multi
set k1 1
set k2 2
set k3 3
discard

watch 命令

它可以为 Redis 事务提供 CAS 乐观锁行为(Check and Set / Compare and Swap),也就是多个线程更新变量的时候,会跟原值做比较,只有它没有被其他线程修改的情况下,才更新成新的值

我们可以用 watch 监视一个或者多个 key,如果开启事务之后,至少有一个被监视key 键在 exec 执行之前被修改了, 那么整个事务都会被取消(key 提前过期除外)。可以用 unwatch 取消

client 1client 2
127.0.0.1:6379> set balance 1000
OK
127.0.0.1:6379> watch balance
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby balance 100
QUEUED
 
 127.0.0.1:6379> decrby balance 100
(integer) 900
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get balance
"900"
 

执行事务可能遇到的问题

把事务执行遇到的问题分成两种,一种是在执行 exec 之前发生错误,一种是在执行 exec 之后发生错误。

  • 在执行 exec 之前发生错误

比如:入队的命令存在语法错误,包括参数数量,参数名等等(编译器错误)。

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set vincent 666
QUEUED
127.0.0.1:6379> hset haoge 9527
(error) ERR wrong number of arguments for 'hset' command
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.

在这种情况下事务会被拒绝执行,也就是队列中所有的命令都不会得到执行。

  •   在执行 exec 之后发生错误

比如,类型错误,比如对 String 使用了 Hash 的命令,这是一种运行时错误。

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 1
QUEUED
127.0.0.1:6379> hset k1 a b
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> get k1
"1"

最后我们发现 set k1 1 的命令是成功的,也就是在这种发生了运行时异常的情况下,只有错误的命令没有被执行,但是其他命令没有受到影响


这个显然不符合我们对原子性的定义,也就是我们没办法用 Redis 的这种事务机制来实现原子性,保证数据的一致

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值