C#Redis 事务操作
一、理论
还是抄前辈的理论知识。
和众多其它数据库一样,Redis作为NoSQL数据库也同样提供了事务机制。在Redis中,MULTI/EXEC/DISCARD/WATCH这四个命令是我们实现事务的基石。相信对有关系型数据库开发经验的开发者而言这一概念并不陌生,即便如此,我们还是会简要的列出Redis中事务的实现特征:
1). 在事务中的所有命令都将会被串行化的顺序执行,事务执行期间,Redis不会再为其它客户端的请求提供任何服务,从而保证了事物中的所有命令被原子的执行。
2). 和关系型数据库中的事务相比,在Redis事务中如果有某一条命令执行失败,其后的命令仍然会被继续执行。
3). 我们可以通过MULTI命令开启一个事务,有关系型数据库开发经验的人可以将其理解为"BEGIN TRANSACTION"语句。在该语句之后执行的命令都将被视为事务之内的操作,最后我们可以通过执行EXEC/DISCARD命令来提交/回滚该事务内的所有操作。这两个Redis命令可被视为等同于关系型数据库中的COMMIT/ROLLBACK语句。
4). 在事务开启之前,如果客户端与服务器之间出现通讯故障并导致网络断开,其后所有待执行的语句都将不会被服务器执行。然而如果网络中断事件是发生在客户端执行EXEC命令之后,那么该事务中的所有命令都会被服务器执行。
5). 当使用Append-Only模式时,Redis会通过调用系统函数write将该事务内的所有写操作在本次调用中全部写入磁盘。然而如果在写入的过程中出现系统崩溃,如电源故障导致的宕机,那么此时也许只有部分数据被写入到磁盘,而另外一部分数据却已经丢失。Redis服务器会在重新启动时执行一系列必要的一致性检测,一旦发现类似问题,就会立即退出并给出相应的错误提示。此时,我们就要充分利用Redis工具包中提供的redis-check-aof工具,该工具可以帮助我们定位到数据不一致的错误,并将已经写入的部分数据进行回滚。修复之后我们就可以再次重新启动Redis服务器了。
二、前戏
命令原型 | 时间复杂度 | 命令描述 | 返回值 |
MULTI | 用于标记事务的开始,其后执行的命令都将被存入命令队列,直到执行EXEC时,这些命令才会被原子的执行。 | 始终返回OK | |
EXEC | 执行在一个事务内命令队列中的所有命令,同时将当前连接的状态恢复为正常状态,即非事务状态。如果在事务中执行了WATCH命令,那么只有当WATCH所监控的Keys没有被修改的前提下,EXEC命令才能执行事务队列中的所有命令,否则EXEC将放弃当前事务中的所有命令。 | 原子性的返回事务中各条命令的返回结果。如果在事务中使用了WATCH,一旦事务被放弃,EXEC将返回NULL-multi-bulk回复。 | |
DISCARD | 回滚事务队列中的所有命令,同时再将当前连接的状态恢复为正常状态,即非事务状态。如果WATCH命令被使用,该命令将UNWATCH所有的Keys。 | 始终返回OK。 | |
WATCH key [key ...] | O(1) | 在MULTI命令执行之前,可以指定待监控的Keys,然而在执行EXEC之前,如果被监控的Keys发生修改,EXEC将放弃执行该事务队列中的所有命令。 | 始终返回OK。 |
UNWATCH | O(1) | 取消当前事务中指定监控的Keys,如果执行了EXEC或DISCARD命令,则无需再手工执行该命令了,因为在此之后,事务中所有被监控的Keys都将自动取消。 | 始终返回OK。 |
三、实战
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr t1
QUEUED
127.0.0.1:6379> incr t2
QUEUED
127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set a 3
QUEUED
127.0.0.1:6379> lpop a
QUEUED
127.0.0.1:6379> set a 4
QUEUED
127.0.0.1:6379> get a
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
4) "4"
127.0.0.1:6379> set t2 tt
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set t2 ttnew
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get t2
"tt"
127.0.0.1:6379>
四、WATCH命令和基于CAS的乐观锁:
在Redis的事务中,WATCH命令可用于提供CAS(check-and-set)功能。假设我们通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,EXEC命令执行的事务都将被放弃,同时返回Null multi-bulk应答以通知调用者事务执行失败。例如,我们再次假设Redis中并未提供incr命令来完成键值的原子性递增,如果要实现该功能,我们只能自行编写相应的代码。其伪码如下:
val = GET mykey
val = val + 1
SET mykey $val
以上代码只有在单连接的情况下才可以保证执行结果是正确的,因为如果在同一时刻有多个客户端在同时执行该段代码,那么就会出现多线程程序中经常出现的一种错误场景--竞态争用(race condition)。比如,客户端A和B都在同一时刻读取了mykey的原有值,假设该值为10,此后两个客户端又均将该值加一后set回Redis服务器,这样就会导致mykey的结果为11,而不是我们认为的12。为了解决类似的问题,我们需要借助WATCH命令的帮助,见如下代码:
WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC
和此前代码不同的是,新代码在获取mykey的值之前先通过WATCH命令监控了该键,此后又将set命令包围在事务中,这样就可以有效的保证每个连接在执行EXEC之前,如果当前连接获取的mykey的值被其它连接的客户端修改,那么当前连接的EXEC命令将执行失败。这样调用者在判断返回值后就可以获悉val是否被重新设置成功。
C#Redis 事务操作的更多相关文章
- Redis事务操作
Redis事务操作 Redis事务本质: 一组命令的集合 , 一个事务中的所有命令都会被序列化 , 在事务执行过程中 , 会按照顺序执行 一次性 : 事务之间的事情,会一次性执行,而不是立刻执行 ...
- Spring Framework 中启动 Redis 事务操作
背景: 项目中遇到有一系列对Redis的操作,并需要保持事务处理. 环境: Spring version 4.1.8.RELEASE Redis Server 2.6.12 (64位) spring- ...
- [Redis-CentOS7]Redis事务操作(六)
事务操作 隔离操作: 事务中所有的命令都会序列化,按顺序执行,不会被其他命令打扰 原子操作: 事务中所有的命令要么全部执行,要么全部不执行 添加事务并执行 127.0.0.1:6379> MUL ...
- Redis - 事务操作
Redis的事务基于四个命令: MULTI EXEC DISCARD WATCH 创建事务 Redis的事务从一个MULTI命令开始,MULTI总会命令返回"ok". 接着就可以开 ...
- Redis - 事务操作与详解
https://blog.csdn.net/J080624/article/details/81669560 写的比较清楚的一个帖子
- spring的声明式事务,及redis事务。
Redis的事务功能详解 http://ghoulich.xninja.org/2016/10/12/how-to-use-transaction-in-redis/ MULTI.EXEC.DISCA ...
- 一次 Redis 事务使用不当引发的生产事故
这是悟空的第 170 篇原创文章 官网:http://www.passjava.cn 你好,我是悟空. 本文主要内容如下: 一.前言 最近项目的生产环境遇到一个奇怪的问题: 现象:每天早上客服人员在后 ...
- python实现redis三种cas事务操作
cas全称是compare and set,是一种典型的事务操作. 简单的说,事务就是为了存取数据库中同一数据时不破坏操作的隔离性和原子性,从而保证数据的一致性. 一般数据库,比如MySql是如何保证 ...
- Redis源代码分析(十七)--- multi事务操作
redis作为一非关系型数据库,居然相同拥有与RDBMS的事务操作,不免让我认为比較吃惊.在redis就专门有文件就是运行事务的相关操作的.也能够让我们领略一下.在Redis的代码中是怎样实现事务操作 ...
随机推荐
- java 注释annotation学习---两篇不错的blog
深入理解Java:注解(Annotation)自定义注解入门 ---- http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html 深入理 ...
- 分形之二叉树(Binary Tree)
上一篇文章讲的是分形之树(Tree),这一篇中将其简化一下,来展示二叉分形树的生长过程. 核心代码: static void FractalBinaryTree(const Vector3& ...
- spark-mllib 密集向量和稀疏向量
spark-mllib 密集向量和稀疏向量 MLlib支持局部向量和矩阵存储在单台服务器,也支持存储于一个或者多个rdd的分布式矩阵 . 局部向量和局部矩阵是用作公共接口的最简单的数据模型. 基本的线 ...
- css绘制特殊图形,meida查询,display inline-box间隙问题以及calc()函数
本文同时发表于本人个人网站 www.yaoxiaowen.com 距离上一篇文章已经一个月了,相比于写代码,发现写文章的确是更需要坚持的事情.言归正传,梳理一下这一个月来,在写ife任务时,有必要记录 ...
- 如何查看 Ubuntu下已安装包版本号
原文链接:https://www.cnblogs.com/the-tops/p/8350662.html 一个软件工具叫做apt-show-versions,通过apt-get安装: $sudo ap ...
- underscore.js源码研究(1)
概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...
- 改变您的HTTP服务器的缺省banner
(以下方法仅针对 IIS Asp.net) 服务器扫描发现漏洞,其中一个是: 可通过HTTP获取远端WWW服务信息 [Microsoft-IIS/8.5] 漏洞描述 本插件检测远端HTTP Serve ...
- saltstack returners 结果转存
returners 是saltstack对minion执行操作后,对返回的数据进行存储,可以存储到一个文件或者数据库当中. 支持的returners http://docs.saltstack.cn/ ...
- python ftplib模块使用
Python中默认安装的ftplib模块定义了FTP类,可用来实现简单的ftp客户端,用于上传或下载文件. ftplib模块常用方法 ftp登陆连接 from ftplib import FTP #加 ...
- spring boot 中使用swagger 来自动生成接口文档
1.依赖包 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swa ...