聊一聊Redis事务

没错,Redis也有事务管理,但是功能很简单,在正式开发中也并不推荐使用。但是面试中有可能会问到,所以本文简单谈一谈Redis的事务。

通过这篇文章,你会了解

  • Redis为什么要提供事务?
  • Redis事务基本指令和使用方法
  • CAS乐观锁是什么?
  • Redis事务为什么不支持回滚?

1. 为什么要用事务

我们知道Redis的单个命令是原子性的,比如 getsetmgetmset等指令。

原子性是指操作是不可分割的,在执行完毕之前不会被任何其它任务或事件中断,也就不会有并发的安全性问题

在涉及到多个命令的时候,如果需要把多个命令设置为一个不可分割的处理序列,就需要用到事务了。

比如,招财和陀螺各有100元,招财给陀螺转了10元,这时候需要在Redis中把招财的金额总数-10,同时需要把陀螺的金额总数+10。这两个操作要么同时成功,要么同时失败,这时候就需要事务了。

实际上,Redis连这个简单的需求都没办法完美做到,至于为啥,接着往下看吧

2. 事务的用法

2.1 5个基本指令

Redis提供了以下5个基本指令,先混个眼熟就行,接下来在案例中进行实操,想记不住都难

命令 格式 作用 返回值 MULTI MULTI 显式开启Redis事务,后续命令将排队,等候使用EXEC进行原子执行 always OK. EXEC EXEC 执行事务中的 commands

队列,恢复连接状态。如果 WATCH

在之前被调用,只有监测中的 Keys

没有被修改,命令才会被执行,否则停止执行(详见下文, CAS

机制)
成功:

返回数组 —— 每个元素对应着原子事务中一个 command

的返回结果;

失败:

返回 NULL Ruby

返回 nil

); DISCARD DISCARD 清除事务中的 commands

队列,恢复连接状态。如果 WATCH

在之前被调用,释放监测中的 Keys

always OK. WATCH WATCH key [key …] 将给出的 Keys

标记为监测态,作为事务执行的条件 always OK. UNWATCH UNWATCH 清除事务中 Keys

的监测态,如果调用了 EXEC

或者 DISCARD

,则没有必要再手动调用 UNWATCH

always OK.

2.2 案例演示

案例场景:招财和陀螺各有100元,招财给陀螺转了10元,这时候需要在Redis中把招财的金额-10,同时需要把陀螺的金额+10。

2.2.1 事务提交

我们首先为陀螺和招财初始化自己的金额;然后使用 MULTI命令 显式开启Redis事务。 该命令总是直接返回OK。此时用户可以发送多个指令,Redis不会立刻执行这些命令,而是将这些指令 依次放入当前事务的指令队列中; EXEC被调用后,所有的命令才会被依次执行。

给陀螺初始化100元
127.0.0.1:6379> set tuoluo 100
OK
给招财初始化100元
127.0.0.1:6379> set zhaocai 100
OK
显式开启事务
127.0.0.1:6379> MULTI
OK
给陀螺增加10元
127.0.0.1:6379(TX)> INCRBY tuoluo 10
QUEUED
给招财减少10元
127.0.0.1:6379(TX)> DECRBY zhaocai 10
QUEUED
执行事务中的所有指令(提交事务)
127.0.0.1:6379(TX)> EXEC
1) (integer) 110
2) (integer) 90

2.2.2 嵌套事务

Redis不支持嵌套事务,多个 MULTI命令和单个 MULTI命令效果相同。

第一次开启事务
127.0.0.1:6379> MULTI
OK
尝试嵌套事务
127.0.0.1:6379(TX)> MULTI
(error) ERR MULTI calls can not be nested
仍然处于第一个事务当中
127.0.0.1:6379(TX)>

2.2.3 放弃事务

如果开启事务之后,中途后悔了怎么办?调用 DISCARD可以清空事务中的指令队列,退出事务。

127.0.0.1:6379> MULTI
OK
在事务中调用DISCARD指令
127.0.0.1:6379(TX)> DISCARD
OK
会退出当前事务
127.0.0.1:6379>

2.2.4 watch指令

假如我们在一个客户端连接中开启了事务,另一个客户端连接修改了这个事务涉及的变量值,将会怎样?

聊一聊Redis事务

client1开启了一个转账的事务,事务开始时招财和陀螺各自拥有100元,在执行 EXEC指令之前,client2将陀螺的余额添加了10元,此时执行 EXEC之后,陀螺最终的金额为120元,招财为90元。

很明显,这种情况下存在数据安全问题。

为此Redis提供了 WATCH的指令,该指令可以为Redis事务提供 CAS乐观锁行为,即多个连接同时更新变量的时候,会和变量的初始值进行比较,只在这个变量的值没有被修改的情况下才会更新成新的值。

2.2.4.1 WATCH用法

对应我们的案例,我们可以使用 WATCH监听一个或多个key,如果开启事务之前,至少有一个被监视的key在 EXEC执行之前被修改了,那么整个事务都会被取消,直接返回 nil(见下面的案例)。 UNWATCHWATCH的反操作。

聊一聊Redis事务

2.2.4.2 CAS机制

CAS(Compare And Swap)比较并替换,是多并发时常用的一种乐观锁技术

CAS需要三个变量信息,分别是内存位置(JAVA中的内存地址,V),旧的预期值(A)和新值(B)。CAS执行时,当且仅当V和预期值A相等时,更新V的值为新值B,否则不执行更新。

聊一聊Redis事务

3. 事务执行出错怎么办

事务执行时可能遇到问题,按照发生的时机不同分为两种:

  • 执行 EXEC之前
  • 执行 EXEC之后

3.1 执行EXEC之前发生错误

比如指令存在语法错误(参数数量不对,指令单词拼错)导致不能进入 commands队列,这一步主要是编译错误,还未到运行时。

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> SET tuoluo
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> EXEC
(error) EXECABORT Transaction discarded because of previous errors.

这种情况下事务会执行失败,队列中的所有指令都不会得到执行。

3.2 执行EXEC之后发生错误

这种错误往往是类型错误,比如对String使用了Hash的命令,这是运行时错误,编译期间不会出错

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> SET tuoluo 100
QUEUED
127.0.0.1:6379(TX)> LPOP tuoluo
QUEUED
127.0.0.1:6379(TX)> EXEC
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value

我们发现, SET tuoluo 100的命令居然执行成功了,也就是在发生了运行时异常的情况下,错误的指令不会被执行,但是其他的命令不会受影响。

聊一聊Redis事务

这种方式显然不符合我们对 原子性的定义,也就是Redis的事务无法实现原子性,无法保证数据一致。

针对这种缺陷,Redis官方也是做了说明的。

4. Redis事务为什么不支持回滚

引自Redis 官方文档

聊一聊Redis事务

为了方便大家理解,我翻译一下就是:

你们程序员的锅,关我们Redis屁事儿!

Redis官方认为,只有在命令语法错误或者类型错误的时候,Redis命令才会执行失败。而且他们认为有这种错误的语法一般也不会进入到生产环境。而且不支持回滚可以使他们有更多时间玩儿Redis运行得更简单快捷。

这种说法多牛!如果出问题就是程序员的问题,写错了还让代码进入生产环境,那就是罪上加罪,你永远赖不着Redis官方。

这可能就是不推荐使用Redis事务的原因了吧,鸡肋是一方面,万一被官方打脸了呢?所以Redis事务的知识稍微了解一下就好,面试被问到能回到上来就可以了。

下期见!

5. 推荐阅读

Original: https://www.cnblogs.com/chanmufeng/p/15901201.html
Author: 蝉沐风
Title: 聊一聊Redis事务

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/579902/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • harbor安装实操笔记

    纸上得来终觉浅,实操一遍吧! 把所有开发的后端服务先在打成镜像,传到私有镜像仓库; 然后在任意的远程机器拉取镜像,然后可采用docker或者docker-compose的方式运行,…

    Java 2023年6月8日
    063
  • 【Java】在IDEA中将Javafx项目打包成为可运行的.jar文件

    在IDEA中将Javafx项目打包成为可运行的.jar文件。 使用JDK17.0.2。 在使用Javafx制作一个图形化界面程序的时候,我遇到了打包文件的难题。按照网上给出的解决方…

    Java 2023年6月8日
    055
  • Docker的常用基本命令

    基本命令 官网:https://docs.docker.com/engine/reference/commandline/docker/ 查看容器CPU状态 docker stat…

    Java 2023年6月5日
    064
  • java 拦截器解决xss攻击

    一、xss攻击 XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaSc…

    Java 2023年5月29日
    069
  • entity序列化问题

    创建entity的时候一般会序列化一下,虽然基本不会用到 ,但是没有序列化的话深克隆就会出错 序列化就是对实例对象的状态(State 对象属性而不包括对象方法)进行通用编码(如格式…

    Java 2023年6月13日
    064
  • 推荐一款企业管理专用低代码工具,实现开发系统自由!

    之前分享过很多类型的文章,但是发现大家对低代码相关的文章,兴致还是比较高的,争议也很大。因为不少人认为低代码太草率,但真正的低代码不仅要负责生成代码,还要负责代码的维护,把它当做一…

    Java 2023年6月5日
    0113
  • SpringMVC的文件上传下载,异常处理,拦截器的小总结

    文件的上传和下载 我们通常在访问网页时会使用到文件的上传与下载的功能,那么他是如何实现的呢? ResponseEntity :用于控制器方法的返回值类型,该控制器方法的返回值就是响…

    Java 2023年6月8日
    060
  • 【翻译】Nginx的HTTP负载均衡

    将请求负载均衡到多个应用实例是一个常用的技术,它起到优化资源使用率、最大化吞吐量、降低延迟、保证容错性。 Nginx是一个非常有效的HTTP负载均衡工具,它将请求分发到多个应用服务…

    Java 2023年5月30日
    058
  • 算法:java打印int类型的二进制格式

    java打印一个int类型的二进制 int类型占4个字节,一个字节8位,int共占32位。java中的int是无符号的(c语言还区分int整形和unsigned int无符号整型)…

    Java 2023年5月29日
    070
  • java程序猿如何练习java版的易筋经?

    故事背景 电视剧《天龙八部》中,阿朱易容后进入少林寺偷走了《易筋经》,她一直想把这本书送给乔峰。耿直的乔峰觉得此书来历不正,不肯接受。几番波折,这本书最后落到聚贤庄庄主游坦之手里。…

    Java 2023年5月29日
    067
  • java高级-续1

    IO 所谓IO就是输出输出(input/output)。一般的理解都是相对于计算机而言的输入输出。 比如: 输出设备:显示器,耳机,音响,打印机….. 输入设备:键盘,…

    Java 2023年6月7日
    0104
  • Spring Batch 批处理框架

    《Spring Batch 批处理框架》基本信息作者: 刘相出版社:电子工业出版社ISBN:9787121252419上架时间:2015-1-24出版日期:2015 年2月开本:1…

    Java 2023年5月30日
    072
  • Java实体映射工具MapStruct详解

    在软件架构中,分层式结构是最常见,各层之间有其独立且隔离的业务逻辑,也因而各层有自己的输入输出对象,也就是代码中见到各种对象,如DO(Data Object)、DTO、Domain…

    Java 2023年5月29日
    058
  • Day4

    package operator;import java.util.Date;//三元运算符public class Demo8 { public static void main…

    Java 2023年6月5日
    067
  • Linux安装Tomcat

    一、下载Tomcat 下载地址:https://tomcat.apache.org/download-80.cgi 二、上传至服务器然后解压 首先确定安装位置,创建文件夹夹。 文件…

    Java 2023年6月8日
    062
  • JavaWeb_(视频网站)_五、视频模块1 视频上传

    视频模块 保存视频流程图 提交博客页面 submit-post-blog.html 提交视频页面 submit-post-video.html 在上传视频请求@RequestMap…

    Java 2023年5月29日
    057
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球