第一篇中介绍了Redis是一个强大的键-值仓储,支持五种灵活的数据结构。其实,Redis还支持其他的一些高级特性:事务、公布与订阅、管道、脚本等,本篇我们来看一下事务。

前一篇中我们提到,在Redis中每一个命令都是原子性的,由于Redis内部的实现是单线程的。当然Redis也支持多个命令之间的事务,只是事务在Redis中相对来说非常easy。不像数据库事务那样涉及传播级别、隔离级别等特性。

使用multi命令開始一个新的事务。exec命令提交,discard命令回滚。假设把信用卡的可用额度存入balance。欠额存入debt,在消费的时候就必须在一个事务内同一时候更新这两个键。
127.0.0.1:6379> set balance 100
OK
127.0.0.1:6379> set debt 0
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby balance 25
QUEUED
127.0.0.1:6379> incrby debt 25
QUEUED
127.0.0.1:6379> exec
1) (integer) 75
2) (integer) 25
127.0.0.1:6379> get balance
"75"
127.0.0.1:6379> get debt
"25"

在multi命令后的其他命令,返回结果都是"QUEUED“,这些命令不会马上运行,仅仅是简单的在Server端缓存起来了。在发出exec命令后,他们才会被一起运行。或者discard命令回滚事务。


在Redis官方文档有指出事务的两个特点:
  1. 事务中的命令都是按着他们进入缓存队列的顺序依次运行的。在事务运行中,Redis不会受理其他client的命令(隔离性)
  2. 事务中的命令,或者所有运行,或者所有不运行。(原子性)
上面的样例是信用卡扣减,但实际中在做扣减时我们须要检查剩余金额是否足够,所以通常会这么做:
redis.multi()
balance = redis.get('balance')
if (balance < amtToSubtract) {
redis.discard()
} else {
redis.decrby('balance', amtToSubtract)
redis.incrby('debt', amtToSubtract)
redis.exec()
}

对于普通数据库事务,上面的代码没问题。但对于Redis事务来说行不通。由于在exec命令之前,全部的命令都被Redis缓存起来了,根本就拿不到balance的值。那类似这样的须要基于已经存在的某个值的事务在Redis中怎样实现呢?答案是Watch命令:
redis.watch('balance')
balance = redis.get('balance')
if (balance < amtToSubtract) {
redis.unwatch()
} else {
redis.multi()
redis.decrby('balance', amtToSubtract)
redis.incrby('debt', amtToSubtract)
redis.exec()
}

通俗点讲,watch命令就是标记一个键。假设标记了一个键,在提交事务前假设该键被别人改动过,那事务就会失败,这样的情况通常能够在程序中又一次再尝试一次。

像上面的样例,首先标记了键balance,然后检查剩余金额是否足够,不足就取消标记。并不做扣减;足够的话,就启动事务进行更新操作,假设在此期间键balance被其他人改动,那在提交事务(运行exec)时就会报错。程序中通常能够捕获这类错误再又一次运行一次。直到成功。


Redis事务失败后不支持回滚
与数据库事务非常重要的一个差别是Redis事务在运行过程中出错后不会回滚。在exec命令后。Redis Server開始一个个的运行被缓存的命令,假设当中某个命令运行出错了,那之前的命令并不会被回滚。

127.0.0.1:6379> set value 1
OK
127.0.0.1:6379> set value2 abc
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr value
QUEUED
127.0.0.1:6379> incr value2
QUEUED
127.0.0.1:6379> exec
1) (integer) 2
2) (error) ERR value is not an integer or out of range
127.0.0.1:6379> get value
"2"
127.0.0.1:6379>

exec提交事务后。在运行到incr value2时错误了(数据类型不对),但事务对value的操作却是生效的。这点能够从后面的get value的返回值看到。

深入浅出Redis(二)高级特性:事务的更多相关文章

  1. Redis进阶实践之五Redis的高级特性

    一.引言    上一篇文章写了Redis的特征,使用场景,同时也介绍了Redis的基本数据类型,redis的数据类型是操作redis的基础,这个必须好好的掌握.今天我们开始介绍一些Redis的高级特性 ...

  2. Redis进阶实践之五Redis的高级特性(转载 5)

    Redis进阶实践之五Redis的高级特性 一.引言 上一篇文章写了Redis的特征,使用场景,同时也介绍了Redis的基本数据类型,redis的数据类型是操作redis的基础,这个必须好好的掌握.今 ...

  3. Redis高级特性---------事务与持久化与发布订阅

    一.redis事务的用法 1.开启事务:multi 2.提交事务:exec   ( queued只是把指令放入队列中,没有执行) 3.取消事务:discard 4.redis事务不能保证同时成功或者失 ...

  4. Redis的高级特性哨兵

    一.哨兵介绍 Redis Sentinel,即Redis哨兵,在Redis 2.8版本开始引入.哨兵的核心功能是主节点的自动故障转移.下面是Redis官方文档对于哨兵功能的描述: 监控(Monitor ...

  5. Redis的高级特性一览

    更多内容,欢迎关注微信公众号:全菜工程师小辉.公众号回复关键词,领取免费学习资料. 应用场景 缓存系统:用于缓解数据库的高并发压力 计数器:使用Redis原子操作,用于社交网络的转发数,评论数,粉丝数 ...

  6. redis多实例与主从同步及高级特性(数据过期机制,持久化存储)

    redis多实例 创建redis的存储目录 vim /usr/local/redis/conf/redis.conf #修改redis的配置文件 dir /data/redis/ #将存储路径配置修改 ...

  7. 【Redis】二、Redis高级特性

    (三) Redis高级特性   前面我们介绍了Redis的五种基本的数据类型,灵活运用这五种数据类型是使用Redis的基础,除此之外,Redis还有一些特性,掌握这些特性能对Redis有进一步的了解, ...

  8. Redis基础用法、高级特性与性能调优以及缓存穿透等分析

     一.Redis介绍 Redis是一个开源的,基于内存的结构化数据存储媒介,可以作为数据库.缓存服务或消息服务使用.Redis支持多种数据结构,包括字符串.哈希表.链表.集合.有序集合.位图.Hype ...

  9. Redis 宝典 | 基础、高级特性与性能调优

    转载:Redis 宝典 | 基础.高级特性与性能调优 本文由 DevOpsDays 本文由简书作者kelgon供稿,高效运维社区致力于陪伴您的职业生涯,与您一起愉快的成长.     作者:kelgon ...

随机推荐

  1. G7或变G6+1?特朗普七国峰会箱友军开炮

    今日导读 G7 峰会刚召开完毕,德国总理默克尔发的一张照片就迅速火遍全球.照片中她身体前倾,像是在质问特朗普,而后者则双手交叉胸前,我自岿然不动,这张火药味十足的照片不禁让人脑补当时剑拔弩张的气氛.到 ...

  2. Archive for required library: 'D:/Program Files/Apache/maven-repository/dom4j/dom4j/1.6.1/dom4j-1.6.1.jar'

    今天导入一个项目工程,发现报错:Archive for required library: 'D:/Program Files/Apache/maven-repository/dom4j/dom4j/ ...

  3. SV学习之interface

    普通的模块使用法:注意我们这里只实现了部分功能....不是完全的读写模块....     module mem_core(   input logic wen,  input logic ren,   ...

  4. Python之队列

    Python之队列 队列:先进先出 队列与线程有关. 在多线程编程时,会起到作用. 作用:确保信息安全的进行交换. 有get 和 put 方法. ''' 创建一个“队列”对象 import Queue ...

  5. awk中RS,ORS,FS,OFS区别与联系

    学习awk时,一定要记得动手去实践,只有在实践中才能发现问题,以下就我在学习中和实践中的经验,总结一下RS,ORS,FS,OFS的区别和联系. 一.OS和ORS 1.RS是记录分隔符,默认的分隔符是\ ...

  6. shell实现ftp命令示例

    一.shell脚本示例: [plain] view plaincopy cd /PATH_YOU_WANT_TO_UPLOAD(DOWNLOAD) ftp -niv <<- EOF ope ...

  7. functools内置装饰器

    def update_wrapper(wrapper, wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES): def ...

  8. 关于srand()rand()的用法

    转自:http://baike.baidu.com/link?url=bhos65ZKp8lEq_6chSsmQv29jHrqjN_IFGVMNod6BuicQ-3oCP5VsEn3RBjXBPvA7 ...

  9. SDWebImage实现分析

    该博文来自南峰子的技术博客,文章从下载和缓存俩个大的组件分析到里面一些核心方法的实现,条理清晰,相对于一些一上来就通篇分析实现思路的技术文章, 这篇的讲解思路明确,框架架构也讲的比较清楚.看完这篇再去 ...

  10. centos下wget时提示unable to resolve host address ...

    网络正常的情况,可以查看/etc/resolv.conf [root@localhost ~]# more /etc/resolv.conf # Generated by NetworkManager ...