WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为。

被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回空多条批量回复(null multi-bulk reply)来表示事务已经失败。

举个例子, 假设我们需要原子性地为某个值进行增 1 操作(假设 INCR 不存在)。

首先我们可能会这样做:

val = GET mykey
val = val + 1
SET mykey $val

上面的这个实现在只有一个客户端的时候可以执行得很好。 但是, 当多个客户端同时对同一个键进行这样的操作时, 就会产生竞争条件。

举个例子, 如果客户端 A 和 B 都读取了键原来的值, 比如 10 , 那么两个客户端都会将键的值设为 11 , 但正确的结果应该是 12才对。

有了 WATCH , 我们就可以轻松地解决这类问题了:

WATCH mykey

val = GET mykey
val = val + 1 MULTI
SET mykey $val
EXEC

使用上面的代码, 如果在 WATCH 执行之后, EXEC 执行之前, 有其他客户端修改了 mykey 的值, 那么当前客户端的事务就会失败。 程序需要做的, 就是不断重试这个操作, 直到没有发生碰撞为止。

这种形式的锁被称作乐观锁, 它是一种非常强大的锁机制。 并且因为大多数情况下, 不同的客户端会访问不同的键, 碰撞的情况一般都很少, 所以通常并不需要进行重试。

了解 WATCH

WATCH 使得 EXEC 命令需要有条件地执行: 事务只能在所有被监视键都没有被修改的前提下执行, 如果这个前提不能满足的话,事务就不会被执行

如果你使用 WATCH 监视了一个带过期时间的键, 那么即使这个键过期了, 事务仍然可以正常执行

WATCH 命令可以被调用多次。 对键的监视从 WATCH 执行之后开始生效, 直到调用 EXEC 为止。

用户还可以在单个 WATCH 命令中监视任意多个键, 就像这样:

redis> WATCH key1 key2 key3
OK

当 EXEC 被调用时, 不管事务是否成功执行, 对所有键的监视都会被取消。

另外, 当客户端断开连接时, 该客户端对键的监视也会被取消。

使用无参数的 UNWATCH 命令可以手动取消对所有键的监视。 对于一些需要改动多个键的事务, 有时候程序需要同时对多个键进行加锁, 然后检查这些键的当前值是否符合程序的要求。 当值达不到要求时, 就可以使用 UNWATCH 命令来取消目前对键的监视, 中途放弃这个事务, 并等待事务的下次尝试。

使用 WATCH 实现 ZPOP

WATCH 可以用于创建 Redis 没有内置的原子操作。

举个例子, 以下代码实现了原创的 ZPOP 命令, 它可以原子地弹出有序集合中分值(score)最小的元素:

WATCH zset
element = ZRANGE zset 0 0
MULTI
ZREM zset element
EXEC

程序只要重复执行这段代码, 直到 EXEC 的返回值不是空多条回复(null multi-bulk reply)即可。

redis中使用 check-and-set 操作实现乐观锁的更多相关文章

  1. Redis中的键值过期操作

    1.过期设置 Redis 中设置过期时间主要通过以下四种方式: expire key seconds:设置 key 在 n 秒后过期: pexpire key milliseconds:设置 key ...

  2. Redis中的事务(多命令)操作

    作为一个nosql数据库,事务是必要功能.但是redis我们是可以理解为它不支持事务操作的,因为它的特征完全不满足我们对事物的正常理解 ps:我不知道是谁一开始提出redis支持事务的,但是我更倾向于 ...

  3. Redis中的key的通用操作

    1.看看所有的key 2.查看以mys开头的key 3.是否存在 4.删除 5.重命名. 6.设置过期时间与所剩的时间 如果没有设置,返回-1. 7.返回类型

  4. redis乐观锁

    乐观锁(又名乐观并发控制,Optimistic Concurrency Control,缩写"OCC"),是一种并发控制的方法.它假设多用户并发的事务在处理时不会彼此互相影响,各事 ...

  5. Redis中的持久化操作

       本篇博客主要来解说一下怎样Redis中的持久化操作,当然了不是一篇理论性的博客,主要还是分享一下在redis中怎样来配置持久化操作.  1.介绍  redis为了内部数据的安全考虑,会把本身的数 ...

  6. 深入理解Redis中的主键失效及其实现机制

    参考:http://blog.sina.com.cn/s/articlelist_1221155353_0_1.html 作为一种定期清理无效数据的重要机制,主键失效存在于大多数缓存系统中,Reids ...

  7. ServiceStack.Redis 中关系操作的局限与bug

    redis是文档型的,nosql中难处理的是关系. 比如人可以发博客,博客可以有分类.按照传统sql中,用户表和分类表都是主表,博客表是从表,有用户的外键和分类的外键 如果使用文档型的思考方式. 为用 ...

  8. 在centos7中安装redis,并通过node.js操作redis

    引言 最近在学习node.js 连接redis的模块,所以尝试了一下在虚拟机中安装cent OS7,并安装redis,并使用node.js 操作redis.所以顺便做个笔记. 如有不对的地方,欢迎大家 ...

  9. 新姿势!Redis中调用Lua脚本以实现原子性操作

    背景:有一服务提供者Leader,有多个消息订阅者Workers.Leader是一个排队程序,维护了一个用户队列,当某个资源空闲下来并被分配至队列中的用户时,Leader会向订阅者推送消息(消息带有唯 ...

随机推荐

  1. MFC中小笔记

    主要记录下一些有啊没啊的MFC东西. 1.单文档 去掉 无标题:在玩的时候用于FindWindow(class,title) BOOL CMainFrame::PreCreateWindow(CREA ...

  2. DIV居中的经典方法

    1. 实现DIV水平居中 设置DIV的宽高,使用margin设置边距0 auto,CSS自动算出左右边距,使得DIV居中. 1 div{ 2 width: 100px; 3 height: 100px ...

  3. Solr7 安装部署 管理界面介绍

    Solr7 安装部署 管理界面介绍 本章重点介绍CentOS 安装部署Solr7 ,Solr的管理界面介绍,添加核心Core配置,Dataimport导入数据,Documents 在线维护索引,Que ...

  4. 51Nod--1051最大子矩阵和(DP入门)

    分析: 我们已经解决了一维的问题(基础篇中的最大子段和问题),现在变成二维了,我们看看能不能把这个问题转化为一维的问题.最后子矩阵一定是在某两行之间的.假设我们认为子矩阵在第i行和第j列之间,我们如何 ...

  5. CCF-201312-3-最大的矩形

    问题描述 试题编号: 201312-3 试题名称: 最大的矩形 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i(1 ≤ ...

  6. OAuth 2.0(网转)

    (一)背景知识 OAuth 2.0很可能是下一代的"用户验证和授权"标准,目前在国内还没有很靠谱的技术资料.为了弘扬"开放精神",让业内的人更容易理解" ...

  7. 第五章 MVC之 FileResult 和 JS请求二进制文件

    一.FileResult 1.简介 表示一个用于将二进制文件内容发送到响应的基类.它有三个子类: FileContentResultFilePathResultFileStreamResult 推荐阅 ...

  8. Java爬虫——模拟登录知乎

    登录界面,首先随意输入一个账号,登录查看发送表单的请求 可以发现请求是Post : https://www.zhihu.com/login/phone_num 发送的表单是 _xsrf: passwo ...

  9. 》》3D轮播

    * { margin: 0; padding: 0; } .slide { position: absolute; top: calc(50% - 150px); left: calc(50% - 3 ...

  10. JDBC中的Statement和PreparedStatement的差别

    以Oracle为例吧 Statement为一条Sql语句生成运行计划, 假设要运行两条sql语句 select colume from table where colume=1; select col ...