redis事务(转载)

原文地址:http://blog.csdn.net/hechurui/article/details/49508749

Redis事务

首先,Redis本身是单线程的。

redis中的事务(transaction)是一组命令的集合。事务同命令一样都是Redis最小的执行单位,一个事务中的命令要么都执行,要么都不执行。Redis事务的实现需要用到 MULTI  EXEC 两个命令,事务开始的时候先向Redis服务器发送 MULTI 命令,然后依次发送需要在本次事务中处理的命令,最后再发送 EXEC 命令表示事务命令结束。MULTI 和 EXEC 中间可以发送DISCARD命令,取消执行。

举个例子,使用redis-cli连接redis,然后在命令行工具中输入如下命令:

  1. 127.0.0.1:6379> MULTI
  2. OK
  3. 127.0.0.1:6379> set url http://qifuguang.me
  4. QUEUED
  5. 127.0.0.1:6379> set title winwill2012
  6. QUEUED
  7. 127.0.0.1:6379> set desc java
  8. QUEUED
  9. 127.0.0.1:6379> EXEC
  10. 1) OK
  11. 2) OK
  12. 3) OK
  13. 127.0.0.1:6379>
  14. 127.0.0.1:6379> get url
  15. "http://qifuguang.me"
  16. 127.0.0.1:6379> get title
  17. "winwill2012"
  18. 127.0.0.1:6379> get desc
  19. "java"
  20. 127.0.0.1:6379>

再举个例子,在命令行工具中输入如下命令:

  1. 127.0.0.1:6379> MULTI
  2. OK
  3. 127.0.0.1:6379> set a a
  4. QUEUED
  5. 127.0.0.1:6379> sett b b
  6. (error) ERR unknown command ‘sett‘
  7. 127.0.0.1:6379> set c c
  8. QUEUED
  9. 127.0.0.1:6379> EXEC
  10. (error) EXECABORT Transaction discarded because of previous errors.
  11. 127.0.0.1:6379> get a
  12. (nil)
  13. 127.0.0.1:6379> get b
  14. (nil)
  15. 127.0.0.1:6379> get c
  16. (nil)
  17. 127.0.0.1:6379>

和前面的例子一样,先输入MULTI最后输入EXEC表示中间的命令属于一个事务,不同的是中间输入的命令有一个错误(set写成了sett),这样因为有一个错误的命令导致事务中的其他命令都不执行了(通过后续的get命令可以验证),可见事务中的所有命令式同呼吸共命运的。

除了保证事务中的所有命令要么全执行要么全不执行外,Redis的事务还能保证一个事务中的命令依次执行而不会被其他命令插入。试想一个客户端A需要执行几条命令,同时客户端B发送了几条命令,如果不使用事务,则客户端B的命令有可能会插入到客户端A的几条命令中,如果想避免这种情况发生,也可以使用事务。

Redis事务错误处理

如果一个事务中的某个命令执行出错,Redis会怎样处理呢?要回答这个问题,首先要搞清楚是什么原因导致命令执行出错:

  1. 语法错误 就像上面的例子一样,语法错误表示命令不存在或者参数错误
    这种情况需要区分Redis的版本,Redis 2.6.5之前的版本会忽略错误的命令,执行其他正确的命令,2.6.5之后的版本会忽略这个事务中的所有命令,都不执行,就比如上面的例子(使用的Redis版本是2.8的)
  2. 运行错误 运行错误表示命令在执行过程中出现错误,比如用GET命令获取一个散列表类型的键值。
    这种错误在命令执行之前Redis是无法发现的,所以在事务里这样的命令会被Redis接受并执行。如果食物里有一条命令执行错误,其他命令依旧会执行(包括出错之后的命令)。比如下例:
  1. 127.0.0.1:6379> MULTI
  2. OK
  3. 127.0.0.1:6379> set key 1
  4. QUEUED
  5. 127.0.0.1:6379> SADD key 2
  6. QUEUED
  7. 127.0.0.1:6379> set key 3
  8. QUEUED
  9. 127.0.0.1:6379> EXEC
  10. 1) OK
  11. 2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
  12. 3) OK
  13. 127.0.0.1:6379> get key
  14. "3"

Redis中的事务并没有关系型数据库中的事务回滚(rollback)功能,因此使用者必须自己收拾剩下的烂摊子。不过由于Redis不支持事务回滚功能,这也使得Redis的事务简洁快速。

回顾上面两种类型的错误,语法错误完全可以在开发的时候发现并作出处理,另外如果能很好地规划Redis数据的键的使用,也是不会出现命令和键不匹配的问题的。

WATCH命令

从上面的例子我们可以看到,事务中的命令要全部执行完之后才能获取每个命令的结果,但是如果一个事务中的命令B依赖于他上一个命令A的结果的话该怎么办呢?就比如说实现类似Java中的i++的功能,先要获取当前值,才能在当前值的基础上做加一操作。这种场合仅仅使用上面介绍的MULTI和EXEC是不能实现的,因为MULTI和EXEC中的命令是一起执行的,并不能将其中一条命令的执行结果作为另一条命令的执行参数,所以这个时候就需要引进Redis事务家族中的另一成员:WATCH命令

换个角度思考上面说到的实现i++的方法,可以这样实现:

  1. 监控i的值,保证i的值不被修改
  2. 获取i的原值
  3. 如果过程中i的值没有被修改,则将当前的i值+1,否则不执行

这样就能够避免竞态条件,保证i++能够正确执行。

WATCH命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行。

有了WATCH命令,我们就可以自己实现i++功能了,伪代码如下:

  1. def incr($key):
  2.     WATCH $key
  3.     $value = GET $key
  4.     if not $value
  5.         $value = 0
  6.     $value = $value + 1
  7.  
  8.     MULTI
  9.     SET $key $value
  10.         result = EXEC
  11.     return result[0]

因为EXEC返回的是多行字符串,使用result[0]表示返回值的第一个字符串。

注意:由于WATCH命令的作用只是当被监控的键被修改后取消之后的事务,并不能保证其他客户端不修改监控的值,所以当EXEC命令执行失败之后需要手动重新执行整个事务。

执行EXEC命令之后会取消监控使用WATCH命令监控的键,如果不想执行事务中的命令,也可以使用UNWATCH命令来取消监控。

WATCH这种方式的锁叫乐观锁。

当然,可以通过redis本身的轮询setnx来实现悲观加锁。

类似于CAS。

MULTI 一次发送多个命令,也可以用来提升性能。这种方式也叫Pipelining。

时间: 2024-08-02 11:01:59

redis事务(转载)的相关文章

Redis——事务&持久化

一.    事务处理 Redis对事务的支持比较简单,或者说它的事务是有缺陷的.它只能保证一个Client发起的事务中的命令可以连续执行,中间不会插入其它client端的命令.缺陷在于,如果一个client将两条命令放到一个事务了,执行的时候第二条命令发送错误,但此时Redis的事务不会回滚第一条命令.如下图: Redis事务的执行原理如下:当client端发起multi命令时,这个连接会进入一个事务上下文,该连接后续的命令不会立即执行,而是先放到一个缓冲队列中,当执行exec命令时,Redis

Redis系列六 Redis事务

Redis事务 1.介绍 在Redis事务中可以一次执行多个命令,本质是一组命令的集合.一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞. 2.事务的作用 一个队列中,一次性.顺序性.排他性的执行一系列命令. 3.事物执行五中情况 case1:正常执行 执行exec全部成功 Case2:放弃事务 执行Discard Case3:全体连坐 在向事物队列中添加命令的时候报错,然后执行Exec会全部失败. Case4:冤头债主 在向事物队列中添加命令的时候没有报错,但在

Redis 事务

Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证: 事务是一个单独的隔离操作:事务中的所有命令都会序列化.按顺序地执行.事务在执行的过程中,不会被其他客户端发送来的命令请求所打断. 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行. 一个事务从开始到执行会经历以下三个阶段: 开始事务. 命令入队. 执行事务. 实例 以下是一个事务的例子, 它先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令

Redis学习笔记(4) Redis事务、生存时间及排序

1. Redis事务 Redis中的事务(transaction)是一组命令的集合,一个事务中的命令要么都执行,要么都不执行.事务的原理是先将属于一个事务的命令发送给Redis,然后再让Redis依次执行这些命令. 127.0.0.1:6379> multi OK 127.0.0.1:6379> sadd user:1:following 2 QUEUED 127.0.0.1:6379> sadd user:2:followers 1 QUEUED 127.0.0.1:6379>

(6)redis 事务

redis对事务的支持目前还比较简单.redis只能保证一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令. 由于redis是单线程来处理所有client的请求的所以做到这点是很容易的.一般情况下redis在接受到一个client发来的命令后会立即处理并 返回处理结果,但是当一个client在一个连接中发出multi命令有,这个连接会进入一个事务上下文,该连接后续的命令并不是立即执行,而是先放到一 个队列中.当从此连接受到exec命令后,redis会顺序的执行

redis学习之——Redis事务(transactions)

Redis事务:可以一次执行多个命令,本质是一组命令的集合.一个事务中的,所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞. 常用命令:MULTI  开启事务  EXEC 提交事务. DISCARD  放弃事务  WATCH  监控事务  UNWATCH   取消监控事务 case1:正常执行                                                   case2:放弃事务 case3:全体连坐                     

Redis事务使用方法

Redis事务 Redis事务是一组命令的集合,也是Redis的最小执行单位之一.一个事务的所有命令,要么都执行,要么都不执行.Redis能保证事务执行期间不会有其他命令插入. 相关命令 命令 格式 说明 DISCARD DISCARD 取消事务 EXEC EXEC 执行事务中的命令 MULTI MULTI 标记一个事务的开始 UNWATCH UNWATCH 取消对key的监视 WATCH WATCH key [key ...] 监视一个或多个key 执行MULTI后,在EXEC或DISCARD

Redis事务的分析及改进

Redis事务的分析及改进 Redis的事务特性 数据ACID特性满足了几条? 为了保持简单,redis事务保证了其中的一致性和隔离性: 不满足原子性和持久性: 原子性 redis事务在执行的中途遇到错误,不会回滚,而是继续执行后续命令:(违反原子性) 事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作: 中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做: 比如: redis 127.0.0.1:7000> multi OK redis 127.0.0.1:7

Redis订阅和发布模式和Redis事务

-------------------Redis订阅和发布模式------------------- 1.概念 Redis 发布订阅(pub/sub)是一种消息通信模式: 发送者(pub)发送消息, 订阅者(sub)接收消息. Redis 客户端可以订阅任意数量的频道. 2.subscribe channel:订阅个指定频道的信息 3.publish channel message:将信息message 发送到指定的频道channel 4.应用场景 1.今日头条订阅号.微信订阅公众号.新浪微博关