redis中的事务、lua脚本和管道的使用场景

19 篇文章 0 订阅

redis中的事务并不像mysql中那么完美,只是简单的保证了原子性。redis中提供了四个命令来实现事务,MULTI:类似于mysql中的BEGIN;EXEC:类似于COMMIT;DISCARD类似于ROLLBACK;WATCH则是用于来实现mysql中类似锁的功能。具体的使用方法非常简单,例如:

127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr count
QUEUED
127.0.0.1:6379> incr count
QUEUED
127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 2

redis事务的实现原理是把事务中的命令先放入队列中,当client提交了exec命令后,redis会把队列中的每一条命令按序执行一遍。如果在执行exec之前事务中断了,那么所有的命令都不会执行;如果执行了exec命令之后,那么所有的命令都会按序执行。但如果在事务执行期间redis被强制关闭,那么则需要使用redis-check-aof 工具对redis进行修复,删除那些部分执行的命令。下面分几种情况讨论下redis事务中需要注意的地方:

1)入队命令语法错误,此时还没有执行exec命令

虽然redis在碰到exec命令之前不会执行事务中的命令,但是,它会对每个命令进行适当的检查,当发现有某些明显的语法错误时,如参数个数不正确,则会在入队时,返回错误信息,并当看到exec命令调用discard命令进行回滚。例如:

127.0.0.1:6379> get name
"Jeff"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name Kate
QUEUED
127.0.0.1:6379> set name
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get name
"Jeff"

2) 当exec执行完毕后,执行其它命令时发生错误

当redis在执行命令时,如果出现了错误,那么redis不会终止其它命令的执行。即只要是正确的命令,无论在错误命令之前还是之后,都会顺利执行。例如:

127.0.0.1:6379> lpush visited "name1"
(integer) 1
127.0.0.1:6379> get name
"Kate"
127.0.0.1:6379> get count
"5"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name Jeff
QUEUED
127.0.0.1:6379> get visited
QUEUED
127.0.0.1:6379> set count 10
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
127.0.0.1:6379> get name
"Jeff"
127.0.0.1:6379> get count
"10"

redis没有实现真正的回滚是因为redis只是一个key-value缓存数据库,如果加上日志回滚,将会影响其效率。

3)事务间的相互影响

事务中最长出现的影响就是同时修改一条记录,而redis中的事务默认没有对此进行处理,如果两个事务同时修改一条记录,首先执行exec的事务的结果将会被覆盖。这里我们可以使用watch命令,该命令用于监控某些具体的key,如果这些key被其它事务修改了,那么本事务再修改时就不会成功,然后返回失败的提示。

T1:
    watch name
    multi
    set name Jeff
    exec
T2:
    watch name
    multi
    set name Kate
    exec

如果T2先提交exec,那么T1提交时则更新失败,此时name依旧是Kate,然后在应用层决定是否需要重新执行该事务。

由于redis事务中的命令在遇到exec命令之前并没有真正的执行,所以我们无法在事务中的命令中使用前面命令的查询结果。我们唯一可以做的就是通过watch保证在我们进行修改时,如果其它事务刚好进行了修改,则我们的修改停止,然后应用层做相应的处理。比如:如果get key 返回的值是true,那么我们set otherkey value,否则什么也不做。这种情况下,虽然可以用事务+watch实现原子操作,但是不免有点太僵硬,很明显这是一个if……else语句。正是因为这个局限,使得lua脚本派上了大的用场。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值