`
足至迹留
  • 浏览: 494780 次
  • 性别: Icon_minigender_1
  • 来自: OnePiece
社区版块
存档分类
最新评论

<redis-8> 4.1 事务及键值监控(watch)

阅读更多
1. 事务
1.1 概述
Redis中的事务(transaction)是一组命令的集合。事务同命令一样都是Redis的最小执行单
位,一个事务中的命令要么都执行,要么都不执行。事务的应用非常普遍,如银行转账过程中A给B汇款,首先系统从A的账户中将钱划走,然后向B的账户增加相应的金额。这两个步骤必须属于同一个事务,要么全执行,要么全不执行。否则只执行第一步,钱就凭空消失了,这显然让人无法接受。
事务的原理是先将属于一个事务的命令发送给Redis,然后再让Redis依次执行这些命令。
例如:
redis>MULTI
OK
redis>SADD "user:1:following" 2
QUEUED
redis>SADD "user:2:followers" 1
QUEUED
redis>EXEC
1) (integer) 1
2) (integer) 1

上面的代码演示了事务的使用方式。
(1)首先使用MULTI命令告诉Redis:“下面我发给你的命令属于同一个事务,你先不要执行,而是把它们暂时存起来。”Redis回答:“OK。”
(2)而后我们发送了两个SADD命令来实现关注和被关注操作,可以看到Redis遵守了承诺,没有执行这些命令,而是返回QUEUED表示这两条命令已经进入等待执行的事务队列中了。
(3)当把所有要在同一个事务中执行的命令都发给Redis后,我们使用EXEC命令告诉Redis将等待执行的事务队列中的所有命令(即刚才所有返回QUEUED的命令)按照发送顺序依次执行。EXEC命令的返回值就是这些命令的返回值组成的列表,返回值顺序和命令的顺序相同。

Redis保证一个事务中的所有命令要么都执行,要么都不执行。如果在发送EXEC命令前客户端断线了,则Redis会清空事务队列,事务中的所有命令都不会执行。而一旦客户端发送了EXEC命令,所有的命令就都会被执行,即使此后客户端断线也没关系,因为Redis中已经记录了所有要执行的命令。
除此之外,Redis的事务还能保证一个事务内的命令依次执行而不被其他命令插入。试想客户端A需要执行几条命令,同时客户端B发送了一条命令,如果不使用事务,则客户端B的命令可能会插入到客户端A的几条命令中执行。如果不希望发生这种情况,也可以使用事务。

1.2 错误处理
如果一个事务中的某个命令执行出错,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)① 功能。为此开发者必须在事务执行出错后自己收拾剩下的摊子(将数据库复原回事务执行前的状态等)。
注释:①事务回滚是指将一个事务已经完成的对数据库的修改操作撤销。

1.3 watch命令介绍
我们已经知道在一个事务中只有当所有命令都依次执行完后才能得到每个结果的返回值,可是有些情况下需要先获得一条命令的返回值,然后再根据这个值执行下一条命令。例如,INCR命令可以使用GET和SET命令自己实现,但会出现竞态条件,伪代码如下:
def incr( key)
value=GET key
if not value
value=0
value= value+1
SET key, value
return value

就目前了解的内容我们肯定会想到可以用事务来实现incr函数以防止竞态条件,可是因为事务中的每个命令的执行结果都是最后一起返回的,所以无法将前一条命令的结果作为下一条命令的参数,即在执行SET命令时无法获得GET命令的返回值,也就无法做到增1的功能了。

为了解决这个问题,我们需要换一种思路。即在GET获得键值后保证该键值不被其他客户端修改,直到函数执行完成后才允许其他客户端修改该键键值,这样也可以防止竞态条件。要实现这一思路需要请出事务家族的另一位成员:WATCHWATCH命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行。监控一直持续到EXEC命令(事务中的命令是在EXEC之后才执行的,所以在MULTI命令后可以修改WATCH监控的键值),如:
redis>SET key 1
OK
redis>WATCH key
OK
redis>SET key 2
OK
redis>MULTI
OK
redis>SET key 3
QUEUED
redis>EXEC
(nil)
redis>GET key
"2"


上例中在执行WATCH命令后、事务执行前修改了key的值(即SET key 2),所以最后事务中的命令SET key 3没有执行,EXEC命令返回空结果。
学会了WATCH命令就可以通过事务自己实现incr函数了,伪代码如下:
def incr( key)
WATCH key
value=GET key
if not value
value=0
value= value+1
MULTI
SET key, value
result=EXEC
return result[0
]
因为EXEC命令返回值是多行字符串类型,所以代码中使用result[0]来获得其中第一个结
果。
提示:
由于WATCH命令的作用只是当被监控的键值被修改后阻止之后一个事务的执行,而不能保证其他客户端不修改这一键值,所以我们需要在EXEC执行失败后重新执行整个函数。

执行EXEC命令后会取消对所有键的监控,如果不想执行事务中的命令也可以使用UNWATCH命令来取消监控。比如,我们要实现hsetxx函数,作用与HSETNX命令类似,只不过是仅当字段存在时才赋值。为了避免竞态条件我们使用事务来完成这一功能:
def hsetxx( key, field, value)
WATCH key
isFieldExists = HEXISTS key, field
if isFieldExists is 1
MULTI
HSET key, field, value
EXEC
else
UNWATCH
return isFieldExists

在代码中会判断要赋值的字段是否存在,如果字段不存在的话就不执行事务中的命令,但需要使用UNWATCH命令来保证下一个事务的执行不会受到影响。
1
0
分享到:
评论

相关推荐

    netty-codec-redis-4.1.74.Final-API文档-中文版.zip

    赠送jar包:netty-codec-redis-4.1.74.Final.jar; 赠送原API文档:netty-codec-redis-4.1.74.Final-javadoc.jar; 赠送源代码:netty-codec-redis-4.1.74.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...

    netty-codec-redis-4.1.73.Final-API文档-中文版.zip

    赠送jar包:netty-codec-redis-4.1.73.Final.jar; 赠送原API文档:netty-codec-redis-4.1.73.Final-javadoc.jar; 赠送源代码:netty-codec-redis-4.1.73.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...

    netty-codec-redis-4.1.73.Final-API文档-中英对照版.zip

    赠送jar包:netty-codec-redis-4.1.73.Final.jar; 赠送原API文档:netty-codec-redis-4.1.73.Final-javadoc.jar; 赠送源代码:netty-codec-redis-4.1.73.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...

    netty-codec-redis-4.1.74.Final-API文档-中英对照版.zip

    赠送jar包:netty-codec-redis-4.1.74.Final.jar; 赠送原API文档:netty-codec-redis-4.1.74.Final-javadoc.jar; 赠送源代码:netty-codec-redis-4.1.74.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-...

    netty-all-4.1.32.Final-sources.jar 最新版netty源码全部包

    netty-codec-redis-4.1.32.Final-sources.jar netty-codec-redis-4.1.32.Final.jar netty-codec-socks-4.1.32.Final-sources.jar netty-codec-socks-4.1.32.Final.jar netty-codec-stomp-4.1.32.Final-sources.jar ...

    redis-trib Redis-x64-3.2.100.rar

    命令行中输入`ruby redis-trib.rb create --replicas 1 &lt;node-1&gt; &lt;node-2&gt; ... &lt;node-n&gt;`,其中`&lt;node-x&gt;`替换为各个Redis实例的IP地址和端口号。 `redme.txt`文件通常是提供关于软件的基本使用说明或注意事项。在...

    phpredis-master.zip php中redis扩展库

    $redis-&gt;subscribe(['channel1', 'channel2'], function($redis, $channel, $message) { echo "Message from $channel: $message\n"; }); // 发布者 $redis-&gt;publish('channel1', 'Hello, world!'); ``` - 事务...

    Redis稳定版 Redis-x64-5.0.14.1.zip

    本次提供的版本是Redis的稳定版——Redis-x64-5.0.14.1,针对64位操作系统设计。在深入探讨Redis之前,我们先了解下Redis的基本特性。 1. **数据类型**: Redis支持五大数据类型:字符串(String)、哈希(Hash)、列表...

    Redis-x64-3.2.100.zip

    本压缩包"Redis-x64-3.2.100.zip"提供了适用于Windows操作系统的Redis 3.2.100版本,该版本为64位系统设计。 1. **Redis的基础概念**: - **键值存储**:Redis基于键值对进行数据存储,键是唯一的标识,值可以是...

    redis-4.0.11 已编译版本

    例如,使用`redis-cli -h &lt;server-ip&gt; -p &lt;port&gt;`命令可以连接到指定IP和端口的Redis服务器。 3. `redis-server`:这是Redis服务器的主进程。启动Redis服务时,你需要运行这个可执行文件。`redis-server /path/to/...

    Redis-x64-5.0.10.zip、Redis-x64-5.0.10.msi

    本文将详细介绍Redis的特性、版本5.0.10的关键改进以及安装Redis-x64-5.0.10.msi的过程。 Redis支持多种数据类型,包括字符串、哈希、列表、集合、有序集合,这些数据结构使得它在缓存、消息队列、计数器等场景中...

    redis-2.8.9

    通过解压并研究"redis-2.8.9"压缩包,你可以深入理解Redis的工作原理,包括它的配置文件、源代码以及如何在本地环境中搭建和运行Redis服务器。同时,这也是学习Redis命令行操作、数据结构设计、持久化策略、复制机制...

    redis-64.3.0.503

    - 配置文件详解:例如,`requirepass yourpassword`设置访问密码,`appendonly yes`启用AOF持久化,`slaveof &lt;master-ip&gt; &lt;master-port&gt;`配置从节点。 4. Windows上的应用: - 客户端工具:Windows用户可以使用`...

    redis-windows-7.2.4.zip

    - 解压"redis-windows-7.2.4.zip",找到`redis-server.exe`启动文件。 - 运行`redis-server.exe`,默认情况下,Redis监听6379端口。 - 可以通过配置文件`redis.windows.conf`修改默认设置,如端口、内存限制、...

    redis-windows-7.0.10.zip

    Redis的核心组件包括`redis-server.exe`(服务器进程)、`redis-cli.exe`(命令行客户端)以及`redis-benchmark.exe`(性能测试工具)等。用户需要通过`redis-server.exe`启动服务,并通过`redis-cli.exe`进行交互式...

    redis-2.8.19+phpredis扩展+redis监控

    `redis-monitor-master.zip`可能包含一个Redis监控工具,这可能是一个自定义的GUI或者命令行工具,用于实时查看Redis的运行状态,如内存使用、命令统计、网络流量等。解压后,按照工具提供的说明进行配置和使用,...

    redis-desktop-manager-0.9.0.616.exe、Redis-x64-3.0.504

    在给定的压缩包文件中,我们有两个与Redis相关的组件:`redis-desktop-manager-0.9.0.616.exe` 和 `Redis-x64-3.0.504.zip`。 1. **redis-desktop-manager-0.9.0.616.exe**: 这是一个Redis桌面管理器的可执行文件...

    redis-3.2.2.gem redis-3.2.2.gem redis-3.2.2.gem

    8. **命令行接口Redis-cli**:Redis-cli工具在3.2版本中也得到了增强,增加了更多的命令和选项,使日常操作更加方便。 9. **安全性和稳定性**:修复了许多已知的bug,增强了系统的安全性,保证了服务的稳定运行。 ...

Global site tag (gtag.js) - Google Analytics