在Redis中,事务是以multi/exec/discard进行的, 其中multi表示事务的开始, exec表示事务的执行,discard表示丢弃事务。

 127.0.0.1:> multi     # 事务的开始
OK
127.0.0.1:> set 1 # 添加命令
QUEUED
127.0.0.1:> set 2
QUEUED
127.0.0.1:> exec # 执行事务
) OK
) OK
127.0.0.1:> get
""
127.0.0.1:> get
""
127.0.0.1:>
 127.0.0.1:> multi     # 事务的开始
OK
127.0.0.1:> set 3 # 添加命令
QUEUED
127.0.0.1:> set
QUEUED
127.0.0.1:> discard #丢弃事务
OK
127.0.0.1:> exec # 此时在执行exec命令会报错。
(error) ERR EXEC without MULTI
127.0.0.1:>

上面演示了一个完整的事务过程,所有的指令在 exec 之前不执行,而是缓存在服务器的一个事务队列中,服务器一旦收到 exec 指令,才开执行整个事务队列,执行完毕后一次性返回所有指令的运行结果。因为 Redis 的单线程特性,它不用担心自己在执行队列的时候被其它指令打断,可以保证他们能得到的“原子性”执行。另外QUEUED没什么特别的意味,就像OK一样,他只是申明命令已经放入缓存队列中了。

redis原子性?


  在mysql中事务会有一个原子执行,如果在事务中一个命令执行时发生错误,其他命令也不会得到执行,但是在redis中是否存在这样的设置? 

 127.0.0.1:> multi          # 事务的开始
OK
127.0.0.1:> set 's'
QUEUED
127.0.0.1:> INCR
QUEUED
127.0.0.1:> set 'ss'
QUEUED
127.0.0.1:> exec
) OK
) (error) ERR value is not an integer or out of range # 因为键为1的值为字符串,不能对其自增,因此报错。
) OK
127.0.0.1:> mget 2 # 键值对2 ‘ss'还是设置成功。
) "s"
) "ss"

从上面我们可以看出,即使在Redis事务中存在错误的命令,也不会妨碍后面的命令执行。

redis中管道


  在上面 Redis 事务例子中,在发送每个指令到事务缓存队列时都要经过一次网络读写,当一个事务内部的指令较多时,需要的网络 IO 时间也会线性增长。所以通常 Redis 的客户端在执行事务时都会结合 pipeline 一起使用,这样可以将多次 IO 操作压缩为单次 IO 操作。来增加性能。 

   import redis

   re = redis.Redis('localhost', , db =)

   p = re.pipeline(transaction=True)
p.multi()
p.set('test_1', 'test——1')
p.set('test_2', 'test_2')
p.execute() # redis 客户端中查询结构
127.0.0.1:> get test_1
"test\xe2\x80\x94\xe2\x80\x941"
127.0.0.1:> get test_2
"test_2"
127.0.0.1:>

 watch命令


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

  有这样一种情况,假如多个用户进行并发操作时,需要将值取出然后操作再回写到对应键的值上,这可能会导致最终的值不是正确的值。这里一种解决办法是分布式锁(悲观所),另一种就是Watch(乐观锁)。

  watch命令会在事务开始之前看住 1 个或多个指定变量,当服务器收到了 exec 指令要顺序执行缓存的事务队列时,Redis 会检查关键变量自 watch 之后,是否被修改了 (包括当前事务所在的客户端)。如果关键变量被人动过了,exec 指令就会返回 null 回复告知客户端事务执行失败,这个时候客户端一般会选择重试。(watch必须再事务之前执行,不能再事务中执行)

   127.0.0.1:> set 'test'
OK
127.0.0.1:> watch test
OK
127.0.0.1:> INCR test # watch之后改变test的值
(integer)
127.0.0.1:> multi # 开始事务
OK
127.0.0.1:> INCR test # 改变test的值
QUEUED
127.0.0.1:> exec # 执行事务
(nil) # 返回空值,事务执行失败。 127.0.0.1:> set 'test_2' # 设置test-
OK
127.0.0.1:> watch test_2 # 监听test_2
OK
127.0.0.1:> multi
OK
127.0.0.1:> INCR test_2 #修改test_2的值
QUEUED
127.0.0.1:> exec # 执行成功
) (integer)

  在py客户端中对于一个值的修改我们可以采用这样形式

 import redis

 def modify_test(client, key):
while True:
client.watch(key)
value = int(client.get(key))
value += # 修改值
pipe = client.pipeline(transaction=True)
pipe.multi()
pipe.set(key, value)
try:
pipe.execute()
break # 修改成功
except redis.WatchError:
continue # 值已经被修改,执行失败
return int(client.get(key)) # 重新获取值 client = redis.StrictRedis()
key = "test"
client.setnx(key, ) # setnx 做初始化
print (modify_test(client, key))

【Redis】事务的更多相关文章

  1. Redis学习笔记~Redis事务机制与Lind.DDD.Repositories.Redis事务机制的实现

    回到目录 Redis本身支持事务,这就是SQL数据库有Transaction一样,而Redis的驱动也支持事务,这在ServiceStack.Redis就有所体现,它也是目前最受业界认可的Redis ...

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

    1. Redis事务 Redis中的事务(transaction)是一组命令的集合,一个事务中的命令要么都执行,要么都不执行.事务的原理是先将属于一个事务的命令发送给Redis,然后再让Redis依次 ...

  3. REDIS 事务机制

    基本事务操作: 任何数据库都必须要保证一种原子执行操作:最基本的原子执行操作肯定是需要提供: 举一个例子来说明: 当对某个Key 做一个统计: 可能不同的Client做它那部分的统计,一段时间后,服务 ...

  4. redis 事务

    概述 相信学过MySQL等其他数据库的同学对事务这个词都不陌生,事务表示的是一组动作,这组动作要么全部执行,要么全部不执行.为什么会有这样的需求呢?看看下面的场景: 微博是一个弱关系型社交网络,用户之 ...

  5. (6)redis 事务

    redis对事务的支持目前还比较简单.redis只能保证一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令. 由于redis是单线程来处理所有client的请求的所 ...

  6. Redis事务的分析及改进

    Redis事务的分析及改进 Redis的事务特性 数据ACID特性满足了几条? 为了保持简单,redis事务保证了其中的一致性和隔离性: 不满足原子性和持久性: 原子性 redis事务在执行的中途遇到 ...

  7. Spring Framework 中启动 Redis 事务操作

    背景: 项目中遇到有一系列对Redis的操作,并需要保持事务处理. 环境: Spring version 4.1.8.RELEASE Redis Server 2.6.12 (64位) spring- ...

  8. 2016022612 - redis事务命令集合

    参考地址:http://www.yiibai.com/redis/redis_transactions.html Redis事务由指令 MULTI 启动,以EXEC结束. 1.multi 用途:事务开 ...

  9. 2016022606 - redis事务

    Redis事务 Redis事务让一组命令在单个步骤执行.事务中有两个属性,说明如下: 1.在一个事务中的所有命令按顺序执行作为单个隔离操作.通过另一个客户端发出的请求在Redis的事务的过程中执行,这 ...

  10. Redis事务和分布式锁

    Redis事务 Redis中的事务(transaction)是一组命令的集合.事务同命令一样都是Redis最小的执行单位,一个事务中的命令要么都执行,要么都不执行.Redis事务的实现需要用到 MUL ...

随机推荐

  1. Linux CentOS中防火墙的关闭及开启端口

    注:CentOS7之前用来管理防火墙的工具是iptable,7之后使用的是Firewall 样例:在CentOS7上安装tomcat后,在linux本机上可以访问tomcat主页,http://ip: ...

  2. mysql命令大全用户管理相关命令

        1.登陆 mysql>mysql -uJDev -p 2.用户管理 mysql>use mysql; 3.查看有哪些登陆用户 mysql> select host,user, ...

  3. MySql数据库笔试题总结

    数据库面试题94577265 1,设有关系EMP(ENO,ENAME,SALARY,DNO),其中各属性的含义依次为职工号.姓名.工资和所在部门号,以及关系DEPT(DNO,DNAME,MANAGER ...

  4. JavaScript:改变 HTML 图像

    JavaScript:改变 HTML 图像 1.代码如下: <!DOCTYPE HTML> <html> <head> <meta charset=" ...

  5. iOS RSA非对称加密测试流程

    非对称加密需要两把钥匙:公钥和秘钥. 单向加密:一般情况下服务器会持有秘钥和公钥,那该怎么使用呢?以注册场景为例,最初服务器持有公钥和密钥. 用户注册时不是直接发送用户名,密码,验证码等明文信息给服务 ...

  6. 优化网站设计(九):减少DNS查找的次数

    前言 网站设计的优化是一个很大的话题,有一些通用的原则,也有针对不同开发平台的一些建议.这方面的研究一直没有停止过,我在不同的场合也分享过这样的话题. 作为通用的原则,雅虎的工程师团队曾经给出过35个 ...

  7. Laravel 5.2 INSTALL- node's npm and ruby's bundler.

    https://getcomposer.org/doc/00-intro.md Introduction# Composer is a tool for dependency management i ...

  8. ldap,openldap-docker,

    ldap basic and usage in devops: https://blog.csdn.net/weixin_42578481/article/details/80863890 maybe ...

  9. teamviewer 卸载干净

    1 点击开始菜单,控制面板,卸载程序,找到软直接卸载2 按住Ctrl+R,输入%AppData%,删除teamview 相关文件夹3 输入regedit打开注册表HKEY_LOCAL_MACHINE\ ...

  10. 重读《深入理解Java虚拟机》二、Java如何分配和回收内存?Java垃圾收集器如何工作?

    线程私有的内存区域随用户线程的结束而回收,内存分配编译期已确定,内存分配和回收具有确定性.共享线程随虚拟机的启动.结束而建立和销毁,在运行期进行动态分配.垃圾收集器主要对共享内存区域(堆和方法区)进行 ...