Redis(十一):Redis的事务功能详解
相关命令
1. MULTI
用于标记事务块的开始。Redis会将后续的命令逐个放入队列中,然后才能使用EXEC命令原子化地执行这个命令序列。
这个命令的运行格式如下所示:
MULTI
这个命令的返回值是一个简单的字符串,总是OK。
2. EXEC
在一个事务中执行所有先前放入队列的命令,然后恢复正常的连接状态。
当使用WATCH命令时,只有当受监控的键没有被修改时,EXEC命令才会执行事务中的命令,这种方式利用了检查再设置(CAS)的机制。
这个命令的运行格式如下所示:
EXEC
这个命令的返回值是一个数组,其中的每个元素分别是原子化事务中的每个命令的返回值。 当使用WATCH命令时,如果事务执行中止,那么EXEC命令就会返回一个Null值。
3. DISCARD
清除所有先前在一个事务中放入队列的命令,然后恢复正常的连接状态。
如果使用了WATCH命令,那么DISCARD命令就会将当前连接监控的所有键取消监控。
这个命令的运行格式如下所示:
DISCARD
这个命令的返回值是一个简单的字符串,总是OK。
4. WATCH
当某个事务需要按条件执行时,就要使用这个命令将给定的键设置为受监控的。
这个命令的运行格式如下所示:
WATCH key [key ...]
这个命令的返回值是一个简单的字符串,总是OK。
对于每个键来说,时间复杂度总是O(1)。
5. UNWATCH
清除所有先前为一个事务监控的键。
如果你调用了EXEC或DISCARD命令,那么就不需要手动调用UNWATCH命令。
这个命令的运行格式如下所示:
UNWATCH
这个命令的返回值是一个简单的字符串,总是OK。
时间复杂度总是O(1)。
示例

redis的事务定义和原理
严格意义来讲,redis的事务和我们理解的传统数据库(如mysql)的事务是不一样的。
Redis中的事务(transaction)是一组命令的集合。
事务同命令一样都是Redis的最小执行单位,一个事务中的命令要么都执行,要么都不执行。事务的原理是先将属于一个事务的命令发送给Redis,然后再让Redis依次执行这些命令。
除此之外,Redis的事务还能保证一个事务内的命令依次执行而不被其他命令插入。试想客户端A需要执行几条命令,同时客户端B发送了一条命令,如果不使用事务,则客户端B的命令可能会插入到客户端A的几条命令中执行。如果不希望发生这种情况,也可以使用事务。
和传统的事务不同(redis不能rollback,也就是不支持回滚)
和传统的mysql事务不同的是,即使我们的加钱操作失败,我们也无法在这一组命令中让整个状态回滚到操作之前。
事务的错误处理
如果一个事务中的某个命令执行出错,Redis会怎样处理呢?要回答这个问题,首先需要知道什么原因会导致命令执行出错。
1.语法错误
语法错误指命令不存在或者命令参数的个数不对。比如:
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。
2.运行错误
运行错误指在命令执行时出现的错误,比如使用散列类型的命令操作集合类型的键,这种错误在实际执行之前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 mykey
val = val + 1
SET mykey $val
但是上述的代码会出现一个问题,因为上面把正常的一个incr(原子递增操作)分为了两部分,那么在多线程(分布式)环境中,这个操作就有可能不再具有原子性了。
研究过java的juc包的人应该都知道cas,那么redis也提供了这样的一个机制,就是利用watch命令来实现的。
watch命令描述
WATCH命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行。监控一直持续到EXEC命令(事务中的命令是在EXEC之后才执行的,所以在MULTI命令后可以修改WATCH监控的键值)
利用watch实现incr
具体做法如下:
WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC
注意点
由于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命令来保证下一个事务的执行不会受到影响。
参考文档
http://redisdoc.com/topic/transaction.html
https://www.cnblogs.com/kyrin/p/5967620.html
Redis(十一):Redis的事务功能详解的更多相关文章
- Redis的事务功能详解
Redis的事务功能详解 MULTI.EXEC.DISCARD和WATCH命令是Redis事务功能的基础.Redis事务允许在一次单独的步骤中执行一组命令,并且可以保证如下两个重要事项: >Re ...
- DBPack SQL Tracing 功能及数据加密功能详解
上周,我们正式发布了 DBPack SQL Tracing 功能和数据加密功能,现对这两个功能做如下说明. SQL Tracing 通过 DBPack 代理开启的全局事务,会自动在 http head ...
- Redis for Windows(C#缓存)配置文件详解
Redis for Windows(C#缓存)配置文件详解 前言 在上一篇文章中主要介绍了Redis在Windows平台下的下载安装和简单使用http://www.cnblogs.com/aehy ...
- redis cluster管理工具redis-trib.rb详解
redis cluster管理工具redis-trib.rb详解 来源 http://weizijun.cn/2016/01/08/redis%20cluster%E7%AE%A1%E7%90%86% ...
- redis cluster 集群 安装 配置 详解
redis cluster 集群 安装 配置 详解 张映 发表于 2015-05-01 分类目录: nosql 标签:cluster, redis, 安装, 配置, 集群 Redis 集群是一个提供在 ...
- redis使用及配置之缓存详解
redis使用及配置之缓存详解 1.Redis的介绍 Redis是一个Key-Value存储系统.它支持存储的value类型有:string(字符串),list(链表), set(无序集合),zset ...
- 高并发架构系列:Redis并发竞争key的解决方案详解
https://blog.csdn.net/ChenRui_yz/article/details/85096418 https://blog.csdn.net/ChenRui_yz/article/l ...
- 分布式-技术专区-Redis并发竞争key的解决方案详解
Redis缓存的高性能有目共睹,应用的场景也是非常广泛,但是在高并发的场景下,也会出现问题:缓存击穿.缓存雪崩.缓存和数据一致性,以及今天要谈到的缓存并发竞争.这里的并发指的是多个redis的clie ...
- .NET ORM框架 SqlSuagr4.0 功能详解与实践【开源】
SqlSugar 4.0 ORM框架的优势 为了未来能够更好的支持多库分布式的存储,并行计算等功能,将SqlSugar3.x全部重写,现有的架构可以轻松扩展多库. 源码下载: https://gith ...
随机推荐
- [Swift]LeetCode788. 旋转数字 | Rotated Digits
X is a good number if after rotating each digit individually by 180 degrees, we get a valid number t ...
- Spring中的IOC_源码_随笔
Spring ioc 叫控制反转,也就是把创建Bean的动作交给Spring去完成. spring ioc 流程大致为 定位-> 加载->注册 先说几个比较有意思的点 1.Spring中 ...
- Java的内部类真的那么难以理解?
01 前言 昨天晚上,我把车停好以后就回家了.回家后才发现手机落在车里面了,但外面太冷,冷到骨头都能感受到寒意——实在是不想返回一趟去取了(小区的安保还不错,不用担心被砸车玻璃),于是打定主意过几个小 ...
- 【JMeter】(3)---MySQL压测
JMeter---MySQL压测 一.添加MySQL驱动jar包 在测试计划(Test Plan)页面添加jar包 二.添加MySQL连接配置 添加线程组右击-->添加(add)-->配置 ...
- 前端打包成桌面应用、以及chrome扩展
前段时间在利用工作之余开发了tomato timer这个蕃茄钟,然后部署到github.io上,由于greatway太厉害,偶尔会有打不开的情况.上周末对比做了扩展和改进,使其成为chrome的插件, ...
- 重排序、hb、ConcurrentHashMap弱一致性(jdk1.6)
double pi = 3.14; //A double r = 1.0; //B double area = pi * r * r; //C 1.A -> B //不满足happens- ...
- java 取汉字首字母
有时候,可能会有一些类似这样的需求: 对于这样的效果,我们可以有类似这样的解决方案: package bys.utils; import java.io.UnsupportedEncodingExce ...
- spring框架应用系列二:component-scan自动扫描注册装配
component-scan自动扫描注册装配 本文系作者原创,转载请注明出处:http://www.cnblogs.com/further-further-further/p/7717331.html ...
- 【c#】RabbitMQ学习文档(五)Topic(主题。通配符模式)
(本实例都是使用的Net的客户端,使用C#编写),说明,中文方括号[]表示名词. 在上一个教程中,我们改进了我们的日志记录系统. 没有使用只能够进行虚拟广播的[Fanout]交换机,而是使用了[Dir ...
- Linux基础知识第五讲,远程管理关机启动网卡命令
目录 一丶学习目标 二丶关机重启命令 三丶 查看或配置网卡信息 1.网卡与IP地址介绍 2.命令介绍 一丶学习目标 关机/重启 shutdown 查看或配置网卡信息 ifconfig ping 远程登 ...