Redis事务介绍
概述
相信学过Mysql等其他数据库的同学对事务这个词都不陌生,事务表示的是一组动作,这组动作要么全部执行,要么全部不执行。为什么会有这样的需求呢?看看下面的场景:
- 微博是一个弱关系型社交网络,用户之间有关注和被关注两种关系,比如两个用户A和B,如果A关注B,则B的粉丝中就应该有A。关注这个动作需要两个步骤完成:在A的关注者中添加B;在B的粉丝中添加A。 这两个动作要么都执行成功,要么都不执行。否则就可能会出现A关注了B,但是B的粉丝中没有A的不可容忍的情况。
- 转账汇款,假设现在有两个账户A和B,现在需要将A中的一万块大洋转到B的账户中,这个动作也需要两个步骤完成:从A的账户中划走一万块;在B的账户中增加一万块。这两个动作要么全部执行成功,要么全部不执行,否则自会有人问候你的!!!
Redis作为一种高效的分布式数据库,同样支持事务。
Redis事务
Redis中的事务(transaction)是一组命令的集合。事务同命令一样都是Redis最小的执行单位,一个事务中的命令要么都执行,要么都不执行。Redis事务的实现需要用到 MULTI 和 EXEC 两个命令,事务开始的时候先向Redis服务器发送 MULTI 命令,然后依次发送需要在本次事务中处理的命令,最后再发送 EXEC 命令表示事务命令结束。
举个例子,使用redis-cli连接redis,然后在命令行工具中输入如下命令:
1 |
127.0.0.1:6379> MULTI |
从输出中可以看到,当输入MULTI命令后,服务器返回OK表示事务开始成功,然后依次输入需要在本次事务中执行的所有命令,每次输入一个命令服务器并不会马上执行,而是返回”QUEUED”,这表示命令已经被服务器接受并且暂时保存起来,最后输入EXEC命令后,本次事务中的所有命令才会被依次执行,可以看到最后服务器一次性返回了三个OK,这里返回的结果与发送的命令是按顺序一一对应的,这说明这次事务中的命令全都执行成功了。
再举个例子,在命令行工具中输入如下命令:
1 |
127.0.0.1:6379> MULTI |
和前面的例子一样,先输入MULTI最后输入EXEC表示中间的命令属于一个事务,不同的是中间输入的命令有一个错误(set写成了sett),这样因为有一个错误的命令导致事务中的其他命令都不执行了(通过后续的get命令可以验证),可见事务中的所有命令式同呼吸共命运的。
如果客户端在发送EXEC命令之前断线了,则服务器会清空事务队列,事务中的所有命令都不会被执行。而一旦客户端发送了EXEC命令之后,事务中的所有命令都会被执行,即使此后客户端断线也没关系,因为服务器已经保存了事务中的所有命令。
除了保证事务中的所有命令要么全执行要么全不执行外,Redis的事务还能保证一个事务中的命令依次执行而不会被其他命令插入。试想一个客户端A需要执行几条命令,同时客户端B发送了几条命令,如果不使用事务,则客户端B的命令有可能会插入到客户端A的几条命令中,如果想避免这种情况发生,也可以使用事务。
Redis事务错误处理
如果一个事务中的某个命令执行出错,Redis会怎样处理呢?要回答这个问题,首先要搞清楚是什么原因导致命令执行出错:
语法错误 就像上面的例子一样,语法错误表示命令不存在或者参数错误
这种情况需要区分Redis的版本,Redis 2.6.5之前的版本会忽略错误的命令,执行其他正确的命令,2.6.5之后的版本会忽略这个事务中的所有命令,都不执行,就比如上面的例子(使用的Redis版本是2.8的)运行错误 运行错误表示命令在执行过程中出现错误,比如用GET命令获取一个散列表类型的键值。
这种错误在命令执行之前Redis是无法发现的,所以在事务里这样的命令会被Redis接受并执行。如果食物里有一条命令执行错误,其他命令依旧会执行(包括出错之后的命令)。比如下例:1
2
3
4
5
6
7
8
9
10
11
12
13
14127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set key 1
QUEUED
127.0.0.1:6379> SADD key 2
QUEUED
127.0.0.1:6379> set key 3
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 key
"3"Redis中的事务并没有关系型数据库中的事务回滚(rollback)功能,因此使用者必须自己收拾剩下的烂摊子。不过由于Redis不支持事务回滚功能,这也使得Redis的事务简洁快速。
回顾上面两种类型的错误,语法错误完全可以在开发的时候发现并作出处理,另外如果能很好地规划Redis数据的键的使用,也是不会出现命令和键不匹配的问题的。
WATCH命令
从上面的例子我们可以看到,事务中的命令要全部执行完之后才能获取每个命令的结果,但是如果一个事务中的命令B依赖于他上一个命令A的结果的话该怎么办呢?就比如说实现类似Java中的i++的功能,先要获取当前值,才能在当前值的基础上做加一操作。这种场合仅仅使用上面介绍的MULTI和EXEC是不能实现的,因为MULTI和EXEC中的命令是一起执行的,并不能将其中一条命令的执行结果作为另一条命令的执行参数,所以这个时候就需要引进Redis事务家族中的另一成员:WATCH命令
换个角度思考上面说到的实现i++的方法,可以这样实现:
- 监控i的值,保证i的值不被修改
- 获取i的原值
- 如果过程中i的值没有被修改,则将当前的i值+1,否则不执行
这样就能够避免竞态条件,保证i++能够正确执行。
WATCH命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令(事务中的命令是在EXEC之后才执行的,EXEC命令执行完之后被监控的键会自动被UNWATCH)
举个例子:
1 |
127.0.0.1:6379> set mykey 1 |
上面的例子中,首先设置mykey的键值为1,然后使用WATCH命令监控mykey,随后更改mykey的值为2,然后进入事务,事务中设置mykey的值为3,然后执行EXEC运行事务中的命令,最后使用get命令查看mykey的值,发现mykey的值还是2,也就是说事务中的命令根本没有执行(因为WATCH监控mykey的过程中,mykey被修改了,所以随后的事务便会被取消)。
有了WATCH命令,我们就可以自己实现i++功能了,伪代码如下:
1 |
def incr($key): |
因为EXEC返回的是多行字符串,使用result[0]表示返回值的第一个字符串。
注意:由于WATCH命令的作用只是当被监控的键被修改后取消之后的事务,并不能保证其他客户端不修改监控的值,所以当EXEC命令执行失败之后需要手动重新执行整个事务。
执行EXEC命令之后会取消监控使用WATCH命令监控的键,如果不想执行事务中的命令,也可以使用UNWATCH命令来取消监控。
声明
原创文章,转载请注明出处,本文链接:http://qifuguang.me/2015/09/30/Redis事务介绍/
如果你喜欢我的文章,请关注我的微信订阅号,更多干货,第一时间与你分享:
Redis事务介绍的更多相关文章
- redis学习(四)redis事务
redis事务 1.redis事务介绍 redis的事务可以理解为一系列串行命令的集合.redis的事务和单条命令一样,都是redis的最小执行单位,因此一个事务内的命令,要么全部执行,要么全部不执行 ...
- 【Redis】Redis 事务
Redis 事务介绍 Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证: 批量操作在发送 EXEC 命令前被放入队列缓存. 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败 ...
- Redis事务与可分布式锁
1 Redis事务 1.1 Redis事务介绍 l Redis的事务是通过MULTI,EXEC,DISCARD和WATCH这四个命令来完成的. l Redis的单个命令都是原子性的,所以 ...
- 探索Redis设计与实现14:Redis事务浅析与ACID特性介绍
本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...
- redis事务及相关命令介绍
redis事务及相关命令介绍 一.概述:和众多其它数据库一样,Redis作为NoSQL数据库也同样提供了事务机制.在Redis中,MULTI/EXEC/DISCARD/WATCH这四个命令是我们实现事 ...
- Lind.DDD.Repositories.Redis层介绍
回到目录 之前已经发生了 大叔之前介绍过关于redis的文章,有缓存,队列,分布式pub/sub,数据集缓存以及仓储redis的实现等等,而今天在Lind.DDD的持久化组件里,redis当然也有一席 ...
- redis 事务
概述 相信学过MySQL等其他数据库的同学对事务这个词都不陌生,事务表示的是一组动作,这组动作要么全部执行,要么全部不执行.为什么会有这样的需求呢?看看下面的场景: 微博是一个弱关系型社交网络,用户之 ...
- Redis事务和分布式锁
Redis事务 Redis中的事务(transaction)是一组命令的集合.事务同命令一样都是Redis最小的执行单位,一个事务中的命令要么都执行,要么都不执行.Redis事务的实现需要用到 MUL ...
- Redis学习——Redis事务
Redis和传统的关系型数据库一样,因为具有持久化的功能,所以也有事务的功能! 有关事务相关的概念和介绍,这里就不做介绍. 在学习Redis的事务之前,首先抛出一个面试的问题. 面试官:请问Redis ...
随机推荐
- skipfish介绍
skipfish 开发语言:C语言 命令行扫描器 主动扫描web安全评估工具 谷歌开发 已经不再进行维护 重点关注web代码 通过两种方式进项扫描:1.字典枚举 2.递归爬网 优点:速度快.支持多路单 ...
- 防csrf详解
CSRF概念:CSRF跨站点请求伪造(Cross—Site Request Forgery),跟XSS攻击一样,存在巨大的危害性,你可以这样来理解: 攻击者盗用了你的身份,以你的名义发送恶 ...
- c++文件对齐
头文件#include <iomanip> 关键词:setw(n),std::left,std::right 实例:输出一个0-4的12*12方阵,要求数字宽度为4,居左对齐,右下角输出出 ...
- PHP 包含文件
1.require test123.php <?php $a=1; 运行文件: <?php require('test123.php'); echo 'Hello!'; echo '< ...
- MFC常用操作
目录: 1.文件操作 1.1.获取文件大小 2.路径操作 2.1.创建多级目录 1.文件操作 1.1.获取文件大小 // 获取文件大小 ULONGLONG size = ; // 文件大小 CFile ...
- Windows环境下,从零开始搭建Nodejs+Express+Ejs框架(二)---安装Express,ejs
安装Express,ejs的前提是一定要先安装nodejs,具体安装方法请查看 http://www.cnblogs.com/tfiremeteor/p/8973105.html 安装Express和 ...
- xml配置文件特殊符号的处理方法
2017.7.19遇到问题:偶然出现“认证失败,请重新登录”的现象 在xml中英文问号“?”是可以被正常解析的,但是以下这几种符号是不能正常解析的:分别是“&”.“<”.“>” ...
- OO学习第一阶段总结
前言 虽然之前接触过java,也写过一些1000行左右的程序.可以说面向对象的思想和java的一些基本语法对我来说是没有难度的,但是这学期的面向对象依然给了我一个下马威.这几次的作业每次都很让我头疼. ...
- 第一次spring冲刺第7天
讨论成员:王俊凯.王逸辉.罗凯杰.马志磊 讨论问题:进行UI设计的详细讨论,虽然结果各有争议,但最终确定了较为简单的布局页面,并且开始收集精美页面的案例 冲刺尚未结束,同志还需努力,致力于最后.
- Unity3D游戏开发——物品存储:List与Dictionary
本篇简介 本文介绍如何将碰撞处理后的物体存储在管理器中,分别用到两种不同的数据结构--List和Dictionary.我们将继续在上一篇博客的编程基础上进行完善. List和Dictionary的区别 ...