Redis事务

事务提供了一种"将多个命令打包,一次性提交并按顺序执行"的机制,提交后在事务执行中不会中断。只有在执行完所有命令后才会继续执行来自其他客户的消息。

Redis中的使用

Redis通过multi,exec,discard,watch实现事务功能。

  1. multi:开始事务
  2. exec:提交事务并执行
  3. discard:取消事务
  4. watch:事务开始之前监视任意数量的键
> multi
OK
> set bookName "Redis"
QUEUED
> get bookName
QUEUED
> sadd tag "Redis" "New Book"
QUEUED
> smembers tag
QUEUED
> exec
1) OK
2) "Redis"
3) (integer) 2
4) 1) "Redis"
2) "New Book"

开始事务

> multi
OK

这个命令将Redis_multi选项打开,让客户端从非事务状态变为事务状态

命令入队

> set bookName "Redis"
QUEUED
> get bookName
QUEUED
> sadd tag "Redis" "New Book"
QUEUED
> smembers tag
QUEUED

在事务状态中,Redis命令并不是立即执行的,而是进入一个先进先出的事务队列。QUEUED表示这个命令已经入了事务队列。

执行事务

> exec
1) OK
2) "Redis"
3) (integer) 2
4) 1) "Redis"
2) "New Book"

当执行exec命令时,Redis根据客户端所保存的事务队列, 以先进先出的方式执行事务队列中的命令: 最先入队的命令最先执行, 而最后入队的命令最后执行。

当exec命令执行完毕时,Redis会将结果保存到一个回复队列,并将回复队列返回给客户端。客户端从事务状态退出,一个事务执行完毕。

discard命令

> multi
OK
> set author "lisi"
QUEUED
> discard
OK
> get author
(nil)

discard取消一个事务的命令,表示这个事务被取消。客户端从事务状态退出,回到非事务状态,Redis_multi选项关闭。

watch命令

# Redis客户端1
> watch letter
OK
> multi
OK
> set letter a
QUEUED
> exec
(nil) # Redis客户端2
> set letter b
OK # Redis客户端1
> get letter
"b"

设置监控letter键,客户端1进入事务,设置letter的value为a,未提交事务。客户端2设置letter的value为b。回到客户端1提交事务返回的结果为nil,调用get命令得到letter为b。这说明当letter键在其他客户端改变后,事务被取消了,不会被执行,返回失败。

watch命令在事务开始之前监视任意数量的键:当调用exce命令执行事务时,如果任意一个被监视的键已经被其他客户端修改了,那么整个事务不再执行,直接返回失败。

事务异常

命令错误

> set letter ac
QUEUED
> get letter ac
(error) ERR wrong number of arguments for 'get' command
> exec
(error) EXECABORT Transaction discarded because of previous errors.

事务中命令异常属于语法错误,将导致事务无法执行。

运行时异常

> multi
OK
> lpush books "Redis"
QUEUED
> incr books
QUEUED
> lpush books "Python"
QUEUED
> lrange books 0 -1
QUEUED
> exec
1) (integer) 1
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) (integer) 2
4) 1) "Python"
2) "Redis"

上面的例子是事务执行到中间遇到失败了,因为不能对一个字符串进行incr命令,事务在遇到命令执行失败后,后续的命令还继续执行,所以books的值能继续得到设置。这种异常只有程序员在代码中避免。

事务的ACID

原子性

原子意味着要么一起成功执行,要么一起失败回滚。Redis提供的所有API都是原子操作。那么Redis事务只要保证在一批操作中保证原子性,但是在运行时异常中,在一个事务中一个命令出现异常,其他命令还是会继续执行,事务没有回滚机制,所以Redis事务是不保证原子性的。

一致性

事务异常

如果命令错误事务无法执行,如果是运行时异常,Redis会将错误包含在返回结果中,并不影响后续执行,所以事务是一致性的。

Redis进程被终结

在纯内存模式下,Redis没有做持久化,重启之后数据库是空白的,所以是事务一致性的。

在RDB模式下,事务并不会在中途执行保存RDB文件的工作,只有在事务执行完后,RDB工作才可能会开始。所以在事务执行过程中Redis进程被杀死,不管成功多少都不会保存到RDB文件中,所以是一致性的。

在AOF模式下,事务部分语句被写入AOF文件并保存成功,不完整的事务被保存到了AOF文件,当重启Redis时,检查AOF文件不完整,Redis退出并报错。需要把这段不完整的事务删除后才能重启成功,所以是一致性的。

在AOF模式下,事务并未被写入AOF文件,所以重启后Redis数据库是最近一次成功保存到AOF文件中的数据。并没有这次事务的数据,所以是以一致性的。

隔离性

Redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。所以事务是带有隔离性的。

持久性

在纯内存模式下,事务肯定不是持续性的。

在RDB模式下,服务器可能在事务执行之后、RDB文件更新之前的这段时间失败,所以 RDB模式下的事务也是不持久的。

在AOF模式下,将命令添加到AOF文件中,但是对文件进行写入并不会马上写到磁盘上,而是先存储到缓冲区。所以数据保存到磁盘上有一段非常小的时间间隔。这种模式下事务也不是持久的。

结语

本人深知水平有限,欢迎指正本文错误之处。

参考资料

《Redis 设计与实现》

《Redis 开发与运维》

《Redis 深度历险:核心原理与应用实践》


欢迎关注公众号:bate喵

专注于Java相关技术:Linux、JVM、SpringCloud、SpringBoot、Docker、Redis、Netty、微服务、高并发等领域,偶尔聊聊学习之道、自控力等方法,致力于成就更好的自己,欢迎大家关注交流,共同成长

一文了解:Redis事务的更多相关文章

  1. Redis事务原理分析

    Redis事务原理分析 基本应用 在Redis的事务里面,采用的是乐观锁,主要是为了提高性能,减少客户端的等待.由几个命令构成:WATCH, UNWATCH, MULTI, EXEC, DISCARD ...

  2. 探索Redis设计与实现14:Redis事务浅析与ACID特性介绍

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  3. Redis事务实现原理

    一:简介 Redis事务通常会使用MULTI,EXEC,WATCH等命令来完成,redis实现事务实现的机制与常见的关系型数据库有很大的却别,比如redis的事务不支持回滚,事务执行时会阻塞其它客户端 ...

  4. Redis 事务支持 ACID 么?

    腾讯面试官:「数据库事务机制了解么?」 「内心独白:小意思,不就 ACID 嘛,转眼一想,我面试的可是技术专家,不会这么简单的问题吧」 程许远:「balabala-- 极其自信且从容淡定的说了一通.」 ...

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

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

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

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

  7. REDIS 事务机制

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

  8. redis 事务

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

  9. (6)redis 事务

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

随机推荐

  1. 用.NET Core实现一个类似于饿了吗的简易拆红包功能

      需求说明 以前很讨厌点外卖的我,最近中午经常点外卖,因为确实很方便,提前点好餐,算准时间,就可以在下班的时候吃上饭,然后省下的那些时间就可以在中午的时候多休息一下了. 点餐结束后,会有一个好友分享 ...

  2. Go语言学习——channel的死锁其实没那么复杂

    1 为什么会有信道 协程(goroutine)算是Go的一大新特性,也正是这个大杀器让Go为很多路人驻足欣赏,让信徒们为之欢呼津津乐道. 协程的使用也很简单,在Go中使用关键字“go“后面跟上要执行的 ...

  3. MySQL 全文索引实现简单版搜索引擎

    目录 前言 使用 三种类型的全文搜索方式 相关参数 测试innodb引擎使用全文索引 准备 使用默认方式创建全文索引 使用ngram分词解析器创建全文索引 结论 前言 只有Innodb和myisam存 ...

  4. RocketMQ与MYSQL事务消息整合

    1.基础理论知识篇“两阶段提交”如果你了解可以跳过这段,当然如果你想深入了解你可以购买相关书籍或去搜索相关资料阅读 两阶段提交分为 正常提交和异常提交或异常回滚 上面是正常提交的示意图,协调者发起预提 ...

  5. Codeforces 777C:Alyona and Spreadsheet(思维)

    http://codeforces.com/problemset/problem/777/C 题意:给一个矩阵,对于每一列定义一个子序列使得mp[i][j] >= mp[i-1][j],即如果满 ...

  6. django基础知识之上传图片:

    上传图片 当Django在处理文件上传的时候,文件数据被保存在request.FILES FILES中的每个键为<input type="file" name="& ...

  7. HTML连载22-序选择器(下)

    一.子元素选择器 1. (1)选中标签之中只有一个子元素的子元素,并且那个标签必须使我们格式中前面指定的标签才行 (2)格式: 标签:only-chirld{属性:值:} (3)举例: p:only- ...

  8. git报错---If no other git process is currently running...

    今天帮同事上传一个代码(预生产环境),当我执行到git add 文件 的时候,出现了如下错误: If no other git process is currently running, this p ...

  9. C++学习书籍推荐《C++标准库(第一版)》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <C++标准程序库:自修教程与参考手册>编辑推荐:C++标准程序库提供了一组通用类别(classes)和界面(interfaes),可大幅扩充C+ ...

  10. 【动态规划例题-数塔问题】-C++

    描述 观察下面的数字金字塔.写一个程序查找从最高点到底部任意处结束的路径,使路径经过数字的和最大.每一步可以 从当前点走到左下方的点也可以到达右下方的点. 在上面的样例中,从13到8到26到15到24 ...