Redis单线程模型事务的实现原理

在使用关系型数据库的时候,为了保证数据的ACID(Atomicity:原子性,Consistency:一致性,Isolation:隔离性,Durability:持久性)我们经常会使用事务,要么全部提交成功,要么失败全部失败,不会存在中间状态。那么我们Redis也会有事务,只不过它不能保证原子性,Redis已经在系统内部进行功能简化,这样可以确保更快的运行速度,因为Redis不需要事务回滚的能力。

redis为我们的事务提供了四个指令:multi(开启事务),discard(丢弃),exec(执行),watch(监视)

基本使用

> multi    #开启事务OK> set a aQUEUED> get aQUEUED> exec     #执行事务1) OK2) "a"> get a"a"

执行原理如下

  1. 当执行multi时,事务开启

  2. 事务里的执行指令都存到一个队列里面,注意这里还是没有执行,可以相当于一个延迟执行

  3. 直到遇见exec指令,我们从队列里面获取指令,然后全部执行

关于事务操作失败的问题

当我们执行事务的时候,队列中有一个执行失败,没执行完的命令会执行吗?答案是会执行的,看下面的结果

> multiOK> set name mangoQUEUED> incr nameQUEUED> set name zhangsanQUEUED> exec1) OK2) (error) ERR value is not an integer or out of range3) OK> get name"zhangsan"

丢弃(discard)

> multiOK> set a aQUEUED> get aQUEUED> discardOK> exec(error) ERR EXEC without MULTI> get a(nil)

discard命令用于取消一个事务,它清空客户端的整个事务队列,然后将客户端从事务状态调整回非事务状态,最后返回字符串OK给客户端,说明事务已被取消。

> multiOK> multi(error) ERR MULTI calls can not be nested

Redis 的事务是不可嵌套的,当客户端已经处于事务状态,而客户端又再向服务器发送multi时,服务器只是简单地向客户端发送一个错误,然后继续等待其他命令的入队。multi命令的发送不会造成整个事务失败,也不会修改事务队列中已有的数据。

监视(watch)

watch命令用于在事务开始之前监视任意数量的键,当调用EXEC命令执行事务时,如果任意一个被监视的键已经被其他客户端修改了,那么整个事务不再执行,直接返回失败。

那么我们来一个失败的情况,具体操作请看图片,我们就不贴代码了

在每个代表数据库的redis.h/redisDb结构类型中,都保存了一个watched_keys字典,字典的键是这个数据库被监视的键,而字典的值则是一个链表,链表中保存了所有监视这个键的客户端。

watch只能在客户端进入事务状态之前执行,在事务状态下发送watch命令会引发一个错误,但它不会造成整个事务失败,也不会修改事务队列中已有的数据。

如果说之前说的分布式锁是悲观锁,那么watch一定是乐观锁,当watch监视的key发生了变化时,我们的事务就不会执行任何操作,当key没有发生任何变化时,我们就执行这个事务。

什么情况下使用事务?

当我们需要一次性完成很多个指令或者我们需要在某次操作中不受其他指令影响,我们可以考虑使用事务,redis事务正如作者所说,我们在使用redis的时候出现异常,那么很多情况是程序设计出现了bug,不要过分依赖redis来做逻辑处理,redis本质是为了提高性能,回滚只会带来更多的问题严重影响实用性和性能。

但是如果需要满足ACID强事务类型,那么我们可以考虑使用lua脚本,但是我们同时需要考虑性能、使用成本等一些方面

 

一名正在抢救的coder

笔名:mangolove

CSDN地址:https://blog.csdn.net/mango_love

GitHub地址:https://github.com/mangoloveYu

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值