Redis事务和watch
redis的事务
严格意义来讲,redis的事务和我们理解的传统数据库(如mysql)的事务是不一样的。
redis中的事务定义
Redis中的事务(transaction)是一组命令的集合。
事务同命令一样都是Redis的最小执行单位,一个事务中的命令要么都执行,要么都不执行。事务的原理是先将属于一个事务的命令发送给Redis,然后再让Redis依次执行这些命令。
Redis保证一个事务中的所有命令要么都执行,要么都不执行。如果在发送EXEC命令前客户端断线了,则Redis会清空事务队列,事务中的所有命令都不会执行。而一旦客户端发送了EXEC命令,所有的命令就都会被执行,即使此后客户端断线也没关系,因为Redis中已经记录了所有要执行的命令。
除此之外,Redis的事务还能保证一个事务内的命令依次执行而不被其他命令插入。试想客户端A需要执行几条命令,同时客户端B发送了一条命令,如果不使用事务,则客户端B的命令可能会插入到客户端A的几条命令中执行。如果不希望发生这种情况,也可以使用事务。
redis事务持久性
事务不过是用队列包裹起了一组 Redis 命令,并没有提供任何额外的持久性功能,所以事务的持久性由 Redis 所使用的持久化模式决定:
- 在单纯的内存模式下,事务肯定是不持久的。
- 在 RDB 模式下,服务器可能在事务执行之后、RDB 文件更新之前的这段时间失败,所以 RDB 模式下的 Redis 事务也是不持久的。
- 在 AOF 的“总是 SYNC ”模式下,事务的每条命令在执行成功之后,都会立即调用 fsync 或 fdatasync 将事务数据写入到 AOF 文件。但是,这种保存是由后台线程进行的,主线程不会阻塞直到保存成功,所以从命令执行成功到数据保存到硬盘之间,还是有一段非常小的间隔,所以这种模式下的事务也是不持久的。
- 其他 AOF 模式也和“总是 SYNC ”模式类似,所以它们都是不持久的。
redis隔离性和一致性
redis事务在执行的过程中,不会处理其它命令,而是等所有命令都执行完后,再处理其它命令(满足隔离性)
redis事务在执行过程中发生错误或进程被终结,都能保证数据的一致性;(详见参考资料1)
事务的应用
事务的应用非常普遍,如银行转账过程中A给B汇款,首先系统从A的账户中将钱划走,然后向B的账户增加相应的金额。这两个步骤必须属于同一个事务,要么全执行,要么全不执行。否则只执行第一步,钱就凭空消失了,这显然让人无法接受。
和传统的事务不同
和传统的mysql事务不同的事,即使我们的加钱操作失败,我们也无法在这一组命令中让整个状态回滚到操作之前
事务的错误处理
如果一个事务中的某个命令执行出错,Redis会怎样处理呢?要回答这个问题,首先需要知道什么原因会导致命令执行出错。
语法错误
语法错误指命令不存在或者命令参数的个数不对。比如:
redis>MULTI OK redis>SET key value QUEUED redis>SET key (error)ERR wrong number of arguments for 'set' command redis> errorCOMMAND key (error) ERR unknown command 'errorCOMMAND' redis> EXEC (error) EXECABORT Transaction discarded because of previous errors.
跟在MULTI命令后执行了3个命令:一个是正确的命令,成功地加入事务队列;其余两个命令都有语法错误。而只要有一个命令有语法错误,执行EXEC命令后Redis就会直接返回错误,连语法正确的命令也不会执行。
这里需要注意一点:
Redis 2.6.5之前的版本会忽略有语法错误的命令,然后执行事务中其他语法正确的命令。就此例而言,SET key value会被执行,EXEC命令会返回一个结果:1) OK。
运行错误
运行错误指在命令执行时出现的错误,比如使用散列类型的命令操作集合类型的键,这种错误在实际执行之前Redis是无法发现的,所以在事务里这样的命令是会被Redis接受并执行的。如果事务里的一条命令出现了运行错误,事务里其他的命令依然会继续执行(包括出错命令之后的命令),示例如下:
redis>MULTI OK redis>SET key 1 QUEUED redis>SADD key 2 QUEUED redis>SET key 3 QUEUED redis>EXEC 1) OK 2) (error) ERR Operation against a key holding the wrong kind of value 3) OK redis>GET key "3"
可见虽然SADD key 2出现了错误,但是SET key 3依然执行了。
Redis的事务没有关系数据库事务提供的回滚(rollback)功能。为此开发者必须在事务执行出错后自己收拾剩下的摊子(将数据库复原回事务执行前的状态等,这里我们一般采取日志记录然后业务补偿的方式来处理,但是一般情况下,在redis做的操作不应该有这种强一致性要求的需求,我们认为这种需求为不合理的设计)。
Watch命令
大家可能知道redis提供了基于incr命令来操作一个整数型数值的原子递增,那么我们假设如果redis没有这个incr命令,我们该怎么实现这个incr的操作呢?
那么我们下面的正主watch
就要上场了。
如何使用watch命令
正常情况下我们想要对一个整形数值做修改是这么做的(伪代码实现):
val = GET mykeyval = val + 1SET mykey $val
但是上述的代码会出现一个问题,因为上面吧正常的一个incr(原子递增操作)分为了两部分,那么在多线程(分布式)环境中,这个操作就有可能不再具有原子性了。
研究过java的juc包的人应该都知道cas,那么redis也提供了这样的一个机制,就是利用watch
命令来实现的。
watch命令描述
WATCH命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行。监控一直持续到EXEC命令(事务中的命令是在EXEC之后才执行的,所以在MULTI命令后可以修改WATCH监控的键值)
利用watch实现incr
具体做法如下:
WATCH mykeyval = GET mykeyval = val + 1MULTISET mykey $valEXEC
和此前代码不同的是,新代码在获取mykey的值之前先通过WATCH命令监控了该键,此后又将set命令包围在事务中,这样就可以有效的保证每个连接在执行EXEC之前,如果当前连接获取的mykey的值被其它连接的客户端修改,那么当前连接的EXEC命令将执行失败。这样调用者在判断返回值后就可以获悉val是否被重新设置成功。
注意点
由于WATCH命令的作用只是当被监控的键值被修改后阻止之后一个事务的执行,而不能保证其他客户端不修改这一键值,所以在一般的情况下我们需要在EXEC执行失败后重新执行整个函数。
执行EXEC命令后会取消对所有键的监控,如果不想执行事务中的命令也可以使用UNWATCH命令来取消监控。
实现一个hsetNX函数
我们实现的hsetNX这个功能是:仅当字段存在时才赋值。
为了避免竞态条件我们使用watch
和事务来完成这一功能(伪代码):
WATCH key isFieldExists = HEXISTS key, field if isFieldExists is 1 MULTI HSET key, field, value EXEC else UNWATCH return isFieldExists
在代码中会判断要赋值的字段是否存在,如果字段不存在的话就不执行事务中的命令,但需要使用UNWATCH命令来保证下一个事务的执行不会受到影响。
优化网络特性
将多个命令打包批量发送到redis服务器执行,减少网络交互,优化性能,可能的解决方案:
- 对于所有的get/set操作,可使用现有的mget/mset指令;
- 对于各种不同类型的更新操作,可使用lua脚本将命令打包后,发送到服务器端一次执行;
转载于:https://www.cnblogs.com/duanxz/p/4745976.html
Redis事务和watch相关推荐
- redis学习之——Redis事务(transactions)
Redis事务:可以一次执行多个命令,本质是一组命令的集合.一个事务中的,所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞. 常用命令:MULTI 开启事务 EXEC 提交事务 ...
- 腾讯二面:Redis 事务支持 ACID 么?
❝ 腾讯面试官:「数据库事务机制了解么?」 「内心独白:小意思,不就 ACID 嘛,转眼一想,我面试的可是技术专家,不会这么简单的问题吧」 程许远:「balabala-- 极其自信且从容淡定的说了一通 ...
- 图解Redis事务机制
来自:Java中文社群 作为关系型数据库中一项非常重要的基础功能--事务,在 Redis 中是如何处理并使用的? 1.前言 事务指的是提供一种将多个命令打包,一次性按顺序地执行的机制,并且保证服务器只 ...
- 【带你重拾Redis】Redis事务
Redis事务 Redis的事务主要依赖于WATCH ,UNWATCH,MULTI , EXEC, DISCARD等命令. 其中 MULTI , EXEC , DISCARD 分别对应关系型数据库的 ...
- redis中有key但是删不掉_一篇图文,搞定Redis事务
在面试的时候,通常会被问到redis是如何实现分布式锁的.如果我们只知道是借助于setnx/setex ,而不了解setnx/setex底层如何实现,那基本上是无法过关的,尤其是大厂.那究竟redis ...
- 十七、Redis事务
一.Redis事务的概念: Redis 事务的本质是一组命令的集合.事务支持一次执行多个命令,一个事务中所有命令都会被序列化.在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求 ...
- Redis - 事务
一.概述 和传统关系型数据库一样,Redis 同样是支持事务的.Redis 的事务可以通过 MULTI/EXEC/DISCARD/WATCH 等命令来实现. 二.事务的 ACID 特性 1). 原子性 ...
- python redis事务_python redis事务源码及应用分析
在多个客户端同时处理相同的数据时,不谨慎的操作很容易导致数据出错.一般的关系型数据库中有事务保证了数据操作的原子性,同样Redis中也设置了事务,可以理解为"将多个命令打包,然后一次性.按顺 ...
- Redis事务(transaction)
Redis事务(transaction) 本文档翻译自: http://redis.io/topics/transactions . MULTI . EXEC . DISCARD 和 WATCH 是 ...
最新文章
- python使用matplotlib可视化包含倒影的柱状图(bar plot with shadow)、配置rcParams坐标轴正确显示负号(-)
- OKEx比特币现金震荡 巴西央行公布新区块链项目
- MYSQL百万级数据,如何优化
- java redis 数据自过期_Java架构-Redis的内存回收策略和Key过期策略,看这篇就够了...
- 20190821:(leetcode习题)验证回文字符串
- Svn常见问题及相关原因
- java linux怎么抓tcp包_Linux使用tcpdump抓取网络数据包示例
- 2007年8月28日 月全食 照片
- PID算法的原理和公式
- 计算机组成原理——输入输出系统
- Java日志框架 - JUL使用详解
- Python3快速入门—5.函数
- Linux 错误信息的查看(摘自鸟哥的私房菜一书)
- springdoc swagger3 文件上传API正确写法
- 2022年国家高新企业认定申报最全问答-财务数据篇
- 访问Oracle数据库的四款工具软件介绍
- C++11初篇(快速了解)
- 安装软件时内存还有很多却依然提示空间不足的解决办法
- C语言不定参数的作用,分享:C语言的三种不定参数,省略号用法
- 解决Win7下苹果笔记本无声音问题