Redis事务的理解与使用

文章目录

  • Redis 事务
    • 1)基本认识
    • 2)事务操作
      • 1.MULTI
      • 2.EXEC
      • 3.错误处理
      • 4.DISCARD
      • 5.WATCH
      • 6.SCRIPT

Redis 事务

官方文档,永远是你学习的第一手资料:Redis 事务

1)基本认识

 谈到事务,大家首先都会联想到 mysql 中复杂但又功能强大的“事务”,和 mysql 相比,redis 所提供的事务简直就是个“弟弟”。我们从 mysql 事务的四大基本特点进行比较:

原子性:

 原子性最初的含义就是把多个操作打包到一起,要么全部执行,要么全部不执行。但是mysql 在原子性这条道路上走的更远,它要求多个操作要么全部执行成功,要么全部不执行,如果其中任一操作执行失败,都会 rollback 确保数据的一致性。

 Redis 事务可以说具有原子性,也可以说没有,这是一个理解角度的问题。Redis 事务确实可以将多个操作打包一起执行,从这方面谈,Redis 是具有原子性的;但是和 mysql 不同,Redis 事务并不保证所有命令执行成功,由于 mysql 的标杆作用“拉高”了原子性的标准,从这一方面说,Redis 并不具有原子性。

 早些版本的 Redis 官网中明确提出了, Redis 事务具有原子性,但现在去看,官网已经把第一句删掉了。看连 Redis 官方都 “怂了”,所以我们还是倾向于认为 Redis 不具有原子性

image-20231121200726156

 那为什么 Redis 不提供和 mysql 一样强大的事务机制呢?首先 mysql 为了实现事务机制付出了巨大的代价,而 Redis 则是主打一个轻量简单,如果和 mysql 一样就丢了自己的特色,那又怎么从这么多数据库中冲杀出来呢?

一致性:

 由于 Redis 并不提供事务回滚机制,当其中某些操作失败时就会造成数据不一致的问题。例如以下这个场景:张三给李四转账 1000 元。张三余额 -1000 的操作成功,但是李四余额 + 1000 的操作失败,而 redis 并不会因为操作执行失败而回滚数据,从而导致数据不一致的问题发生

持久性:

 mysql 中又 redo log 保证事务的持久性,但是 redis 事务本身并不具有持久性,持久化还得依赖redis的 rdb 或者 aof 机制。但是否开启持久化,是redis-server自己的决定,和事务本身无关

隔离性:

 Redis 没有也不需要隔离性。隔离性是针对并发读写的问题而引入了,而 Redis 是一个单进程的数据库,不存在这方面的烦恼。

2)事务操作

1.MULTI

  • multi 指令用于开启一个事务

    127.0.0.1:6379> multi
    OK
    
  • Redis 服务端为每一个客户端维护一个事务命令队列,multi 后所有命令(除了 exec)都会被添加到队列中而不是立即执行(queued 状态)

    127.0.0.1:6379> set key1 1
    QUEUED
    127.0.0.1:6379> set key1 2
    QUEUED
    

2.EXEC

  • exec 指令用于按次序一次性执行事务队列中命令

    127.0.0.1:6379> exec
    1) OK
    2) OK
    127.0.0.1:6379> get key1
    "1"
    

3.错误处理

在 Redis 事务中存在两种类型的错误:

  • 在调用 exec 前发生错误,例如某个指令中存在语法错误。当这种错误发生时,整个事务都会被直接丢弃

    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> get key1
    QUEUED
    127.0.0.1:6379> abc
    (error) ERR unknown command `abc`, with args beginning with: 
    127.0.0.1:6379> exec
    (error) EXECABORT Transaction discarded because of previous errors.
    
  • 在调用 exec 期间发生的错误。在这种情况下,Redis 会继续执行剩余的命令,不管某些命令是否失败。

    127.0.0.1:6379> FLUSHALL
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set key1 1
    QUEUED
    127.0.0.1:6379> LPOP key1
    QUEUED
    127.0.0.1:6379> set key2 2
    QUEUED
    127.0.0.1:6379> get key2
    QUEUED
    127.0.0.1:6379> EXEC
    1) OK
    2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
    3) OK
    4) "2"
    

    上面的案例也验证了 Redis 事务只能保证多条一起执行,但并不保证所有的命令都会执行成功。失败了也不会数据回滚,因而存在一致性的问题

4.DISCARD

  • discard 指令用于终止取消当前正在执行的事务,队列中的所有指令都会被直接丢弃

    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> get key1
    QUEUED
    127.0.0.1:6379> get key2
    QUEUED
    127.0.0.1:6379> discard
    OK
    127.0.0.1:6379> exec
    (error) ERR EXEC without MULTI
    
  • 当前没有正在执行的事务,则 discard 指令无效

    127.0.0.1:6379> discard
    (error) ERR DISCARD without MULTI
    

5.WATCH

用法:

  • 在执行事务期间,某个键值被其他客户端修改了,其结果就容易令人产生歧义,例如下面这个场景

    timeclient_1client_2
    t1execute command multi
    t2execute command set key1 1
    ……
    t3execute command set key1 2
    t4execute command exec
  • watch 与事务配合使用,它允许你监视多个 key,如果在事务的执行期间任何一个键被其他客户端修改,都会导致当前事务全部丢弃,从而确保了事务执行期间数据的一致性。watch 的作用时间从 multi 开始到执行 exec 结束。

    // client1
    127.0.0.1:6379> mset key1 1 key2 2
    OK
    127.0.0.1:6379> watch key1 key2
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> mget key1 key2
    QUEUED
    127.0.0.1:6379> exec 
    (nil)    // 事务执行失败
    
    // client2:在client1事务执行期间进行如下修改
    127.0.0.1:6379> incr key1
    (integer) 2
    127.0.0.1:6379> decr key2
    (integer) 1
    
  • unwatch 的作用与 watch 相反,它用于清除对所有 key 的 “watch”。在执行 exec 或者 client 退出时,所有的 key 都会 “unwatched”

原理:

 watch 本质就是一把乐观锁,通过CAS机制实现:每个 "watched " 变量都有一个初始版本号,修改变量会让其版本号变大,在执行 exec 时会比较当前版本号与 watch 时的版本号是否一致,如果不一致,说明变量在事务执行期间发生了修改,当前事务就会被 discard

案例:

下面是官方文档提供的一个使用案例,通过 watch 去创造一个新的原子操作:

WATCH zset
element = ZRANGE zset 0 0
MULTI
ZREM zset element
EXEC

 从 zset 中删除一个元素有两部:1)找到最小的元素 2) 将最小的元素删除。如果删除失败,说明最小值被其他客户端修改,那么我们就重复上面操作,直到删除一个最小值

6.SCRIPT

 任何 redis 事务能完成的操作,我们都可以使用 redis script 完成。redis script 天生就有把多个指令打包执行的能力,感兴趣的可以去网上找找 lua 脚本操作 redis 的教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/178232.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HTML新手入门笔记整理:HTML基本标签

结构标签 <html> </html> 告诉浏览器这个页面是从<html> 开始&#xff0c;到 </html>结束 <head> </head> 网页的头部&#xff0c;用于定义一些特殊内容&#xff0c;如页面标题、定时刷新、外部文件等。 <body> </body> …

Vue 3 渲染机制解密:从模板到页面的魔法

Vue 3 渲染机制解密 前言Vue 3的响应性系统1. **Reactivity API:**2. **Proxy 对象:**3. **Getter 和 Setter:**4. **依赖追踪:**5. **批量更新:**6. **异步更新:**7. **递归追踪:**8. **删除属性:** 虚拟DOM的角色1. **减少直接操作真实 DOM:**2. **高效的批量更新:**3. **跨平…

[论文笔记] Scaling Laws for Neural Language Models

概览: 一、总结 计算量、数据集大小、模型参数量大小的幂律 与 训练损失呈现 线性关系。 三个参数同时放大时,如何得到最佳的性能? 更大的模型 需要 更少的样本 就能达到相同的效果。 </

浅谈Python装饰器原理与用法分析

前言 本文实例讲述了Python装饰器原理与用法。分享给大家供大家参考&#xff0c;具体如下&#xff1a; 1、装饰器的本质是函数&#xff0c;主要用来装饰其他函数&#xff0c;也就是为其他函数添加附加功能 2、装饰器的原则: (1) 装饰器不能修改被装饰的函数的源代码 (2) 装…

智能卡接口芯片解决方案

一、基本概述 HCM8035是一款简洁且低成本的智能IC卡模拟接口芯片。内嵌升压模块&#xff0c;支持5V,3V,1.8V全电压读写。具有全面的安全保护机制&#xff0c;包括ESD保护&#xff0c;端口短路保护&#xff0c;电源上掉电保护。外围元件数目少&#xff0c;采用QFN32L封装。 今…

如何用惯性动作捕捉系统,快速创建数字人三维动画?

在动画制作领域&#xff0c;惯性动作捕捉技术已经逐渐成为一种重要的制作手段。通过动捕设备能够将动捕演员真实的动作转化为数字数据&#xff0c;然后在动画中再现这些动作。为了创造出逼真、流畅的数字人动画&#xff0c;惯性动作捕捉系统成为了一大工具。 根据采集方式的不…

感恩节的习俗 Custom of Family Dinner

感恩节是美国最普遍庆祝的传统节日之一。在每年11月的第四个星期四&#xff0c;感恩节如期而至。Thanksgiving is one of the most universally celebrated traditional American holidays. Every year, Thanksgiving arrives on the fourth Thursday of November without fail…

为Oracle链接服务器使用分布式事务

1 现象 在SQL Server中创建指向Oracle的链接服务器&#xff0c;SQL语句在事务中向链接服务器插入数据。返回链接服务器无法启动分布式事务的报错。 2 解决 在Windows平台下&#xff0c;SQL Server依赖分布式事务协调器&#xff08;MSDTC&#xff09;来使用分布式事务&#xff0…

光量子计算再创融资高峰!法国 Quandela获投5000万欧元

​&#xff08;图片来源&#xff1a;网络&#xff09; 法国光量子计算公司Quandela致力于开发首台光量子计算机&#xff0c;目前已获得超过5,000万欧元的巨额融资。投资者包括通过“法国2030计划”获得的法国政府支持以及银行合作伙伴、个人。新的投资者包括法国投资公司Seren…

Vue2系列 — 渲染函数 (render + createElement)

官网文档&#xff1a;https://v2.cn.vuejs.org/v2/guide/render-function.html 1 render 函数 render 函数 不使用模板&#xff0c;使用 js 生成虚拟 dom 2 createElement() 接受的参数&#xff1a; 参数1 节点类型参数2 attribute参数3 子节点 3 DEMO <template>&…

阿里云发送短信

官方代码如下&#xff1a; // This file is auto-generated, dont edit it. Thanks. package com.aliyun.sample;import com.aliyun.tea.*;public class Sample {/*** 使用AK&SK初始化账号Client* param accessKeyId* param accessKeySecret* return Client* throws Excep…

4G5G智能执法记录仪在保险公司车辆保险远程定损中的应用

4G智能执法记录仪&#xff1a;汽车保险定损的**利器 随着科技的不断进步&#xff0c;越来越多的智能设备应用到日常生活中。而在车辆保险定损领域&#xff0c;4G智能执法记录仪的出现无疑是一大**。它不仅可以实现远程定损&#xff0c;还能实现可视化操作、打印保单以及数据融…

贪心算法及相关例题

目录 什么是贪心算法&#xff1f; leetcode455题.分发饼干 leetcode376题.摆动序列 leetcode55题.跳跃游戏I leetcode45题.跳跃游戏II leetcode621题.任务调度器 leetcode435题.无重叠空间 leetcode135题.分发糖果 什么是贪心算法&#xff1f; 贪心算法更多的是一种思…

函数式编程-Stream流笔记-三更草堂

函数式编程-Stream流 1. 概述 1.1 为什么学&#xff1f; 能够看懂公司里的代码 大数量下处理集合效率高 代码可读性高 消灭嵌套地狱 //查询未成年作家的评分在70以上的书籍 由于数据中作家和书籍可能出现重复&#xff0c;需要进行去重 List<Book> bookList new Ar…

深入理解Java虚拟机-GC

深入理解Java虚拟机-GC 当需要排查各种内存溢出、内存泄漏时&#xff0c;当垃圾回收成为系统到达更高并发量的瓶颈时&#xff0c;我们必须对内存动态分配和内存回收技术这样的“自动化”技术采用必要的监控和调节。 Java堆和方法区&#xff1a;一个接口的多个实现类需要的内存…

[计算机网络实验]头歌 实验二 以太网帧、IP报文分析(含部分分析)

目录 第1关&#xff1a;Wireshark基本使用入门 【实验目的】 【实验环境】 【本地主机、平台虚拟机之间数据传递】 wireshark基本用法】 1、wireshark主界面 2、抓取分组操作 3、Wireshark窗口功能 4、筛选分组操作 【实验操作】 ​编辑 第2关&#xff1a;Ethernet帧…

Leaflet结合Echarts实现迁徙图

效果图如下&#xff1a; <!DOCTYPE html> <html><head><title>Leaflet结合Echarts4实现迁徙图</title><meta charset"utf-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0">…

C++:利用哈希表对unordered系列容器模拟实现

文章目录 unordered容器使用[在长度 2N 的数组中找出重复 N 次的元素](https://leetcode.cn/problems/n-repeated-element-in-size-2n-array/description/) 底层结构初步改造哈希表基本逻辑的实现 最终实现 本篇主要总结unordered系列容器和其底层结构 unordered容器使用 从使…

MYSQL索引使用注意事项

索引使用注意事项&#xff1a; 1.索引列运算 不要在索引列上进行运算操作&#xff0c;否则索引将失效&#xff1b; 2.字符串不加引号 字符串类型使用时&#xff0c;不加引号&#xff0c;否则索引将失效&#xff1b; 3.模糊查询 如果仅仅是尾部模糊匹配&#xff0c;索引将不会失…

使用EasyPlayer播放H.265视频流

使用EasyPlayer播放H.265视频流 EasyPlayer流媒体视频播放器 EasyPlayer流媒体视频播放器 EasyPlayer流媒体视频播放器可支持H.264与H.265编码格式&#xff0c;性能稳定、播放流畅&#xff0c;能支持RTSP、RTMP、HLS、FLV、WebRTC等格式的视频流播放&#xff0c;并且已实现网页…