Redis 之四:Redis 事务和乐观锁
事务特点
Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:
-
批量操作在发送 EXEC 命令前被放入队列缓存。
-
收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。不具备原子性。
-
在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
Redis 事务的缺点
- 不支持回滚: Redis事务在执行
EXEC命令之前,如果通过WATCH检测到监视的键发生了变化,则会拒绝执行整个事务并返回空结果。但请注意,这并不是传统数据库中的“回滚”操作,因为Redis不会自动撤销已经执行过的命令,它仅仅是在事务中止时阻止后续未执行的命令。 - 命令排队一次性执行: 在Redis事务中,所有命令会被放入一个队列,在
EXEC命令被执行时按照先进先出的顺序执行,期间不能中断或插入新的命令。这意味着事务开始后无法根据中间结果动态调整事务内的操作,降低了灵活性。 - 无隔离级别: Redis的事务没有提供如SQL数据库那样的多种事务隔离级别(如读已提交、可重复读等)。所有事务都是在单线程环境下的串行化执行,因此避免了脏读、不可重复读等问题,但这也意味着在高并发场景下可能会有性能瓶颈。
- Watch-Multi-Exec模式的问题: 使用
WATCH进行乐观锁控制时,一旦网络延迟或者客户端异常导致事务未能及时执行,监视的数据可能已经被其他客户端修改,此时即便事务最终执行,也无法保证数据一致性。 - 批量操作不具备完全的原子性: 虽然Redis的所有命令在服务器内部是原子执行的,但在一个事务中多个命令的组合并不能视为一个原子操作。例如,事务中包含对多个key的操作,即使其中一个操作失败,事务内其它命令也会被执行完毕,而不是整体取消。
三个阶段
一个事务从开始到执行会经历以下三个阶段:
- 开始事务。
- 命令入队。
- 执行事务。
案例步骤
从multi 开始,一系列操作,最后执行 exec ,批量执行处理
127.0.0.1:6379> multi
OK
127.0.0.1:6379> keys *
QUEUED
127.0.0.1:6379> hset person name zhang age 34
QUEUED
127.0.0.1:6379> hdel person age
QUEUED
127.0.0.1:6379> hset person email zhang@sina.com
QUEUED
127.0.0.1:6379> exec
1) 1) "listz"2) "book"3) "word"4) "myset"5) "mydest"6) "student"
2) (integer) 2
3) (integer) 1
4) (integer) 1
127.0.0.1:6379> hgetall person
1) "name"
2) "zhang"
下表列出了 redis 事务的相关命令:
| 序号 | 命令及描述 |
|---|---|
| 1 | [DISCARD] 取消事务,放弃执行事务块内的所有命令。 |
| 2 | [EXEC] 执行所有事务块内的命令。 |
| 3 | [MULTI] 标记一个事务块的开始。 |
| 4 | [UNWATCH] 取消 WATCH 命令对所有 key 的监视。 |
| 5 | [WATCH key [key ...]] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。 |
乐观锁
乐观锁(Optimistic Locking)是一种在数据库并发控制中的策略,它假设多用户同时访问同一数据时发生冲突的概率较低,并且在更新数据之前并不立即进行加锁操作。与悲观锁不同的是,悲观锁在读取数据时就直接获取并持有锁,直到事务结束才释放;而乐观锁则是:
- 读取阶段:当一个事务想要修改数据时,它不会立即锁定该数据行。每个事务在读取数据时都会记录下当时的数据版本号或时间戳等信息。
- 验证阶段:在事务提交更新操作前,会再次检查当前要更新的数据是否自上次读取以来没有被其他事务修改过。这通常通过比较数据的版本号来实现,如果版本号未变,则认为可以安全地执行更新。
- 更新阶段:如果数据版本验证通过(即版本号仍为事务开始读取时的版本),则执行更新操作,并将数据版本号递增,确保后续的并发事务能够识别出这次更新。如果发现版本号已被改变,说明存在并发修改,此时乐观锁机制会让当前事务回滚,并提示并发错误,通常需要重新读取数据并尝试更新。
Redis 乐观锁
Redis 乐观锁是一种在分布式系统中实现并发控制的机制,它借鉴了数据库领域的乐观并发控制思想,并通过Redis提供的命令来实现。在乐观锁策略下,假定多个客户端同时访问同一数据时,通常不会发生冲突或至少冲突的概率较低。因此,在读取数据时不立即加锁,而是在更新数据前才去检查在此期间是否有其他客户端修改过该数据。
在Redis中,乐观锁主要通过WATCH命令和事务(multi/exec)来实现:
- WATCH命令:客户端使用
WATCH命令监视一个或多个键,这些键的数据状态将被记录下来。当执行WATCH后,如果任何被监视的键在事务提交前发生了变化,则整个事务将会被打断,即不会执行EXEC命令内的操作。 - 事务处理:客户端可以将一系列命令放入事务中,使用
MULTI开始一个事务块,然后执行一系列的操作指令。最后,用EXEC命令尝试提交事务。只有在所有被WATCH的键自WATCH以来未被其他客户端改变的情况下,事务中的命令才会被执行。
举例来说:
- 客户端A对一个键进行
WATCH。 - 然后客户端A开始一个事务,并准备修改这个键的值。
- 在事务提交(
EXEC)之前,如果其他客户端改变了该键的值,那么客户端A的事务在执行EXEC时会发现数据已经被修改,从而导致事务回滚,不执行任何操作。
下面具体来举例:
主要是 watch 和 multi 两个命令配合使用,实现乐观锁
watch 监视某一个可能变化的 key。然后开启事务,一系列操作放入队列等待执行,如果在exec 执行事务之前,其他的客户端对监视的key 做了修改,则exec 执行结果为nil 。什么都不执行。
127.0.0.1:6379> watch mm #### 开始监视 mm 变量
OK
127.0.0.1:6379> multi #### 开启事务
OK
127.0.0.1:6379> incrby mm 500 #### 第一次 给 mm 加500 操作放入队列
QUEUED
127.0.0.1:6379> incrby mm 500 #### 第二次 给 mm 加500 操作放入队列
QUEUED
### 此时去另一个客户端执行修改操作
另一个客户端的修改操作
127.0.0.1:6379> decrby mm 500 #### 给 mm 减去500
(integer) -500 #### 立即起效,结果为 -500
然后再回原来执行事务的客户端执行下面操作:
127.0.0.1:6379> exec #### 开始执行事务
(nil) #### 没有任何执行结果 因为乐观锁起作用了
127.0.0.1:6379> get mm #### 再次查看结果
"-500" #### 是另一个客户端的执行结果。刚才加的两次500 无效。
127.0.0.1:6379> watch mm #### 再次监控
OK
127.0.0.1:6379> multi #### 开启事务
OK
127.0.0.1:6379> incrby mm 500 #### 加500
QUEUED
127.0.0.1:6379> incrby mm 500 #### 加500
QUEUED
127.0.0.1:6379> exec #### 执行事务
1) (integer) 0
2) (integer) 500 #### 执行成功,因为其他客户端没有修改被监视的变量 mm .
127.0.0.1:6379> 相关文章:
Redis 之四:Redis 事务和乐观锁
事务特点 Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证: 批量操作在发送 EXEC 命令前被放入队列缓存。 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。不具备原子性。 在事务执…...
C# WPF编程-创建项目
1.创建新项目 选择“WPF应用程序”》“下一步” 设置项目 设置项目名称,保存位置等参数>下一步 3.选择框架 4.项目创建成功 5.运行项目...
密码学及其应用(应用篇15)——0/1背包问题
1 问题背景 背包问题是一个经典的优化问题,在计算机科学和运筹学中有着广泛的应用。具体到你提到的这个问题,它是背包问题中的一个特例,通常被称为0/1背包问题。这里,我们有一系列的正整数 ,以及一个正整数,…...
基于springboot+vue的实验室管理系统(前后端分离)
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 主要内容:毕业设计(Javaweb项目|小程序|Pyt…...
华为OD技术面试案例5-2024年
背景 985本计算机专业,目标院校。 1.15 投递 在某BOSS上投递的简历,HR人很nice,非常负责任。 1.19 收到机试通知 第一题是一个哈夫曼编码,第三题是一个动态规划,机试整体难度不算高,刷leetcode hot100…...
【QT+QGIS跨平台编译】之五十五:【QGIS_CORE跨平台编译】—【qgsmeshcalcparser.cpp生成】
文章目录 一、Bison二、生成来源三、构建过程一、Bison GNU Bison 是一个通用的解析器生成器,它可以将注释的无上下文语法转换为使用 LALR (1) 解析表的确定性 LR 或广义 LR (GLR) 解析器。Bison 还可以生成 IELR (1) 或规范 LR (1) 解析表。一旦您熟练使用 Bison,您可以使用…...
Unity(第二十部)效果 粒子、线条和拖尾
1、粒子系统 粒子系统介绍 Unity 粒子系统是 Unity 引擎中用于创建和控制粒子效果的工具。它可以模拟各种自然现象,如火焰、烟雾、雨滴等,也可以用于创建特效,如魔法光芒、爆炸效果等。 粒子系统组成 在 Unity 中,粒子系统由发射…...
全量知识系统问题及SmartChat给出的答复 之6 三套工具之1
Q15. 提出想法和问题 前面说过,DDD在我要设计的全量知识系统中位于中间层,是专门用来解决“知识汤”问题的。 解决的思路就是以将为在特定领域中的公司经营提供一个责任-权限平面为目的,帮助他们调整商业模式以及组建恰当的组织,…...
[RoarCTF 2019]Easy Calc
这题考查的是: 字符串解析特性目录读取文件内容读取 字符串解析特性详解:PHP字符串解析特性 ($GET/$POST参数绕过)(含例题 buuctf easycalc)_参数解析 绕过-CSDN博客 ascii码查询表:ASCII 表 | 菜鸟工具 …...
完美解决 git 报错fatal: Not a git repository (or any of the parent directories): .git
问题描述 错误提示是找不到.git文件,无法执行git指令,意思是 当前你要提交的文件夹中没有.git这个文件 解决方案 执行如下命令: git init...
electron无法设置自己的图标?渲染进程require报错?
electron无法设置自己的图标? 极有可能是图标太大,或者宽高不同 我推荐的网址icon转换 选着20x20一般就可以 渲染进程无法使用require?一直报错? webPreferences: {nodeIntegration: true, enableRemoteModule: true, contextIsolation: …...
vscode连接服务器与FileZilla上传到服务器
https://www.cnblogs.com/qiuhlee/p/17729647.html(这个是vscode连接服务器) 主机:就是服务器的主机号 使用者名称:比如ALmax的用户名 密码:比如ALmax的密码...
练习 1 Web EasySQL极客大挑战
CTF Week 1 EasySQL极客大挑战 BUUCTF 典中典复习 Web SQL 先尝试输入,找一找交互页面 check.php 尝试万能语句 a’ or true SQL注入:#和–的作用 get传参只能是url编码,注意修改编码,输入的字符串要改成url格式。 POST请求和…...
matlab生成模拟的通信信号
matlab中rand函数生成均匀随机分布的随机数,randn生成正态分布的随机数; matlab来模拟一个通信信号; 通信信号通过信道时,研究时认为它会被叠加上服从正态分布的噪声; 先生成随机信号模拟要传输的信号,s…...
Altair® SimLab® 以流程为导向的多学科仿真环境,可连接CAD 的多物理场工作流程
Altair SimLab 以流程为导向的多学科仿真环境,可连接CAD 的多物理场工作流程 SimLab 是一种以流程为导向的多学科仿真环境,能够精确分析复杂装配体的性能表现。包括结构、热和流体动力学在内的多物理场可以通过高度自动化的建模任务轻松设置,有助于大幅…...
Python爬虫-爬取B站番剧封面
本文是本人最近学习Python爬虫所做的小练习。如有侵权,请联系删除。 页面获取url 代码 import requests import os import re# 创建文件夹 path os.getcwd() /images if not os.path.exists(path):os.mkdir(path)# 当前页数 page 1 # 总页数 total_page 2# 自动…...
AI时代的产品文案秘籍:如何用AI提升效率
人工智能写作工具:解放双手,创作不停歇 在当前人工智能技术飞速发展的背景下,越来越多的个体已经开始利用这一AI写作工具,以显著提高自己的工作效率。这不仅标志着人工智能服务于人类的宏伟时代的到来,更是人人可用的创…...
前端架构: 脚手架通用框架封装之入口文件开发(教程一)
脚手架入口文件开发 创建脚手架项目: abc-cli $ mkdir abc-cli && cd abc-cli 全局安装 lerna, $ npm i -g lerna 基于 lerna 完成项目初始化 $ lerna init 基于 lerna 创建脚手架 cli $ lerna create cli一路回车 好现在生成了一个 cli 的模板,目前需要…...
吴恩达《机器学习》学习笔记
本笔记资料来源于 http://www.ai-start.com/ml2014/,该笔记来自于https://blog.csdn.net/dadapongi6/article/details/105668394,看了忘,忘了看,再看一遍。 时间统计:2024.2.29 5个番茄钟,从week1开始&…...
【FPGA】线性反馈移位寄存器(LFSR)的Verilog实现
什么是移位寄存器 移位寄存器:是指多个寄存器并排相连,前一个寄存器的输出作为下一个寄存器的输入,寄存器中存放的数据在每个时钟周期向左或向右移动一位。 下面的右移移位寄存器因为左侧没有有效输入,所以在第4个时钟周期&…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...
若依登录用户名和密码加密
/*** 获取公钥:前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...
