介绍

  1. redis的目标的是: 简洁,高效,由于事务本身就是一个很复杂的东西,所有我们不能把事务做的太复杂。
  • DISCARD 取消事务,放弃执行事务块内的所有命令。

  • EXEC 执行所有事务块内的命令。

  • MULTI 标记一个事务块的开始。

  • UNWATCH 取消 WATCH 命令对所有 key 的监视。

  • WATCH key [key ...] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

    MULTI 和 EXEC

  127.0.0.1:6379> multi
OK
127.0.0.1:6379> lpush fruits orange
QUEUED
127.0.0.1:6379> lpush fruits nut
QUEUED
127.0.0.1:6379> lpush fruits apple
QUEUED
127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 2
3) (integer) 3

我们发现命令是一起执行的,如果说我的某一条命令执行失败,会回滚吗?

答案是不会回滚。看看下面的原子性。

原子性

事务的原子性是指要么事务全部成功,要么全部失败,那么 Redis 事务执行是原子性的么? 下面我们来看一个特别的例子。

> multi
OK
> set books iamastring # 执行成功
QUEUED
> incr books # 执行失败
QUEUED
> set poorman iamdesperate # 执行成功
QUEUED
> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
> get books
"iamastring"
> get poorman
"iamdesperate

  上面的例子是事务执行到中间遇到失败了,因为我们不能对一个字符串进行数学运算,事务在遇到指令执行失败后,后面的指令还继续执行,所以 poorman 的值能继续得到设置。

  到这里,你应该明白 Redis 的事务根本不能算「原子性」,而仅仅是满足了事务的「隔离性」,隔离性中的串行化——当前执行的事务有着不被其它事务打断的权利。

Watch

我在执行lpush的时候,lpush被其他人改变了。

需求:在写multi的时候,不可以有其他的命令更改 “队列”中的集合。

出现并发问题,因为有多个客户端会并发进行操作。我们可以通过 Redis 的分布式锁来避免冲突,这是一个很好的解决方案。分布式锁是一种悲观锁,那是不是可以使用乐观锁的方式来解决冲突呢?

Redis 提供了这种 watch 的机制,它就是一种乐观锁。有了 watch 我们又多了一种可以用来解决并发修改的方法。 watch 的使用方式如下:

127.0.0.1:6379> watch msg
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set msg "hello wolrd"
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get msg
"12345"
127.0.0.1:6379>

注意事项

Redis 禁止在 multi 和 exec 之间执行 watch 指令,而必须在 multi 之前做好盯住关键变量,否则会出错。

.net操练,在StackExchange.Redis又该怎么做?

更复杂的事实是StackExchange.Redis使用的是多路复用器的方式。

我们不能只让并发调用方发布 WATCH / UNWATCH / MULTI / EXEC / DISCARD:这应该是混合在一起的。所以一个额外的抽象被给出:另外会让使事情更简单准确:约束。约束是预定义测试包括 WATCH 某种类型的测试并对结果进行检查。如果所有的约束都通过了,那么要么是以 MULTI / EXEC 发布(从事务开始,到执行整个事务块);要么是以 UNWATCH 发布(取消 WATCH 命令对所有 key 的监视)。阻止命令于其它调用方被混合在一起;所以例子可以是:

注意:从 CreateTransaction 返回的对象最后都是调用异步方法来执行命令(Execute方法最终也是调用ExecuteAsync,具体可以看源码):由于不知道每个操作的结果,除非在 Execute 或 ExecuteAsync 操作完成后。如果操作没有被执行,所有的Task 将被标记为取消,否则在命令执行后你可以获取每个正常的结果。

       static void Transaction()
{
using (ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost:6379"))
{
IDatabase db = redis.GetDatabase();
ITransaction tran = db.CreateTransaction();
//为该事务添加先决条件
//强制指定指定的哈希字段不能存在。
tran.AddCondition(Condition.HashNotExists("transactionDemo", "UniqueID"));
tran.HashSetAsync("transactionDemo", "UniqueID","Unnn");
bool committed = tran.Execute();
Console.WriteLine(committed); //第1次执行,true,因为不存在,后面执行false,因为存在
}
}

通过 When 的内置操作

还应该注意的是,Redis已经为我们预料到了许多常见的场景(特别是:key/hash的存在,就像上面一样),还有单操作(single-operation)原子命令的存在。 通过 When 来访问,所以前面的示例也可以这样来实现:

var newId = CreateNewId();
bool wasSet = db.HashSet(custKey, "UniqueID", newId, When.NotExists);

注意:When.NotExists 会使用命令 HSETNX 而不会使用 HSET

HSETNX:如果字段已经存在于哈希表中,操作无效。

Redis实战 - 5事务:multi、exec和watch的更多相关文章

  1. redis实战之事务与持久化

    1. 事务描述 (1)什么是事务 事务,就是把一堆事情绑在一起,按顺序的执行,都成功了才算完成,否则恢复之前的样子 事务必须服从ACID原则,ACID原则分别是原子性(atomicity).一致性(c ...

  2. 二十四 Redis消息订阅&事务&持久化

    Redis数据类型: Redis控制5种数据类型:String,list,hash,set,sorted-set 添加数据,删除数据,获取数据,查看有多少个元素,判断元素是否存在 key通用操作 JR ...

  3. .Net Redis实战——事务和数据持久化

    Redis事务 Redis事务可以让一个客户端在不被其他客户端打断的情况下执行多个命令,和关系数据库那种可以在执行的过程中进行回滚(rollback)的事务不同,在Redis里面,被MULTI命令和E ...

  4. redis multi exec

    multi(),返回一个redis对象,并进入multi-mode模式,一旦进入multi-mode模式,以后调用的所有方法都会返回相同的对象,直到exec()方法被调用. phpredis是php的 ...

  5. Redis 实战 —— 07. 复制、处理故障、事务及性能优化

    复制简介 P61 关系型数据库通常会使用一个主服务器 (master) 向多个从服务器 (slave) 发送更新,并使用从服务器来处理所有读请求. Redis 也采用了同样的方法实现自己的复制特性,并 ...

  6. Redis实战:如何构建类微博的亿级社交平台

    微博及 Twitter 这两大社交平台都重度依赖 Redis 来承载海量用户访问.本文介绍如何使用 Redis 来设计一个社交系统,以及如何扩展 Redis 让其能够承载上亿用户的访问规模. 虽然单台 ...

  7. Redis实战篇

    Redis实战篇 1 Redis 客户端 1.1 客户端通信 原理 客户端和服务器通过 TCP 连接来进行数据交互, 服务器默认的端口号为 6379 . 客户端和服务器发送的命令或数据一律以 \r\n ...

  8. Redis 中的事务分析,Redis 中的事务可以满足ACID属性吗?

    Redis 中的事务 什么是事务 1.原子性(Atomicity) 2.一致性(Consistency) 3.隔离性(Isolation) 4.持久性(Durability) 分析下 Redis 中的 ...

  9. Redis系列之key操作命令与Redis中的事务详解(六)

    序言 本篇主要目的有二: 1.展示所有数据类型中key的所有操作命令,以供大家学习,查阅,更深入的挖掘redis潜力. 2.掌握redis中的事务,让你的数据完整性一致性拥有更优的保障. redis命 ...

随机推荐

  1. fastclick原理剖析及其用法

    移动端点击延迟事件 移动端浏览器在派发点击事件的时候,通常会出现300ms左右的延迟. 原因: 移动端的双击会缩放导致click判断延迟.这是为了检查用户是否在做双击.为了能够立即响应用户的点击事件, ...

  2. java并发编程 | 线程详解

    个人网站:https://chenmingyu.top/concurrent-thread/ 进程与线程 进程:操作系统在运行一个程序的时候就会为其创建一个进程(比如一个java程序),进程是资源分配 ...

  3. [HNOI2010]城市建设

    [HNOI2010]城市建设 玄学cdq O(nlog^2n)的动态最小生成树 其实就是按照时间cdq分治+剪枝(剪掉一定出现和不可能出现的边) 处理[l,r]之间的修改以及修改之后的询问,不能确定是 ...

  4. plsql 永久注册码适用个版本

    注册码:Product Code:4t46t6vydkvsxekkvf3fjnpzy5wbuhphqzserial Number:601769 password:xs374ca

  5. (模拟 打好基础)nyoj1363-计划日

    1363-计划日 内存限制:256MB 时间限制:3000ms 特判: No通过数:21 提交数:79 难度:1 题目描述: 为什么花那么多时间.精力还是学不好学不通,如何把握各科目的重难点,期中和期 ...

  6. easyUI文本框获得焦点,失去焦点

    easyUI帮助文档对于文本框的操作没有提供直接获得焦点,或者失去焦点的方法,我们可以采用以下写法来实现. 获得焦点: $('input',$('#文本框Id').next('span')).focu ...

  7. Linux进程管理工具Supervisor

    简述 Supervisor是用Python开发的一套通用的进程管理程序,能将一个普通的命令行进程变为后台daemon,并监控进程状态,异常退出时能自动重启. 它是通过fork/exec的方式把这些被管 ...

  8. Ext.Net的一例Ext Undefined解决办法

    在运行的产品里发现了一例Ext Undefined报错.经过仔细排查原因是一个Ext.net按钮控件前端显示部分使用了<% if()  <%> 动态控制输出Html脚本(有对应的后端 ...

  9. C#代码使用Process类调用SWFTools工具

    一.Process类调用SWFTools工具将PDF文档转为swf文档 1 string cmdStr = "D:\\SWFTools\\pdf2swf.exe"; string ...

  10. Ubuntu通过ADB连接手机

    参考 ubuntu14.04 下android studio连接手机 安装 adb $sudo apt install adb $sudo lsusb 得到ID为 Bus Device : ID 12 ...