当前位置: 首页 > news >正文

Redis-事务与管道

Redis-事务与管道

  • 一、事务
    • 1. Redis事务命令
    • 2. 事务控制
  • 二、管道
  • 总结


一、事务

什么是事务?
事务是一组操作的集合,它是不可分割的工作单元
事务会把所有的操作作为一个整体提交或撤销,这些操作要么同时成功,要么同时失败

Redis事务

  • 可以一次执行多个命令,本质上是一组命令的集合
  • 一个事务中所有的命令都会序列化(排序),这些命令会串行执行而不会被其他命令插入
  • Redis命令在提交前命令是不会被实际执行的

总结:是一个队列中,一次性、顺序性、排他性的一系列命令

SESSION A
1
2
3
 
SESSION B
事务1234567

Redis事务与MySQL事务的不同?
最大的不同点:
1. Redis事务不支持回滚
2. Redis事务中的命令不会出错了就不往后执行(事务内的多条命令可能部分失败)
3. 无隔离机制,一致性弱
4. Redis命令在提交前命令是不会被实际执行的。


1. Redis事务命令

正常执行事务

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> keys *
QUEUED
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> exec
1) 1) “k1”
2) “k2”
2) OK
3) OK

QUEUED => 将命令已经放到队列中

放弃事务

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v11
QUEUED
127.0.0.1:6379(TX)> set k2 v22
QUEUED
127.0.0.1:6379(TX)> discard
OK
127.0.0.1:6379> get k1
“v1”

事务出错的两种情况

  1. 语法错误=>撤销,全部不执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v11
QUEUED
127.0.0.1:6379(TX)> set k2
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k2
"v2"
  1. 逻辑错误 => 正确的命令会执行,错误的命令不执行(部分执行成功)
127.0.0.1:6379> set name cici
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v11
QUEUED
127.0.0.1:6379(TX)> incr name
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (error) ERR value is not an integer or out of range
127.0.0.1:6379> get k1
"v11"
127.0.0.1:6379> get name
"cici"

2. 事务控制

watch监控 => 乐观锁

  • 悲观锁:认为每次去拿数据时别人都会修改数据,每次使用数据前先给数据上锁,确保别人不会来修改数据(上锁->使用->释放)
  • 乐观锁:认为每次去拿数据时别人都不会修改数据,所以不会上锁,只在更新的时候去检查数据是否被更新。

在事务中,当检查到被watch的数据有更新时,整个事务内的操作命令都会失效

SESSION 1

1. 
127.0.0.1:6379> set price 100
OK3. 
127.0.0.1:6379> watch price
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set price 200
QUEUED
127.0.0.1:6379(TX)> 5. 
127.0.0.1:6379(TX)> exec
(nil)
127.0.0.1:6379> get price 
"300"

SESSION 2

2. 
127.0.0.1:6379> get price
"100"
127.0.0.1:6379> 4. 
127.0.0.1:6379> set price 300
OK
127.0.0.1:6379> get price
"300"

在exec前使用的unwatch将数据取消监控数据/断开连接可以取消监控数据
事务操作会正常执行

SESSION 1

1.
127.0.0.1:6379> watch price
OK
127.0.0.1:6379> get price
"300"
127.0.0.1:6379> 3. 
127.0.0.1:6379> unwatch
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set price 100
QUEUED
127.0.0.1:6379(TX)> get price
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) "100"

SESSION 2

2. 
127.0.0.1:6379> set price 200
OK
127.0.0.1:6379> get price
"200"

二、管道

如果客户端频繁地连接RedisSever并执行命令,是否能优化?

1秒内100次,这些操作可能是连续执行的命令
get k1
get k2
get k3

Client ----- Server
发送命令-排队-执行-返回结果
发送命令-排队-执行-返回结果
发送命令-排队-执行-返回结果
发送命令-排队-执行-返回结果

发送命令(10条)-排队-执行-返回结果(10条)

管道
可以一次性发送多条命令给服务器,服务器依次处理完成后,通过一条响应一次性将结果返回

特点:

  • 管道缓冲的指定只会依次执行,不保证原子性。如果指令发生异常,后续指令正常执行。
  • 管道缓存的命令不能过多,否则造成客户端阻塞时间过久,服务器返回数据过多,占用过多内存

管道的使用

  • 将命令写到文件中
[root@rocky ~]# vim cmd.txt
set k1 v111
set k2 v222
hset k3 name cici
lpush mylist 1 2 3 4[root@rocky ~]# cat cmd.txt | redis-cli -a 12345678 --pipe
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
All data transferred. Waiting for the last reply...
Last reply received from server.
errors: 0, replies: 4127.0.0.1:6379> keys *
1) "k1"
2) "price"
3) "mylist"
4) "name"
5) "k3"
6) "k2"
127.0.0.1:6379> get k1
"v111"
127.0.0.1:6379> lrange mylist 0 -1
1) "4"
2) "3"
3) "2"
4) "1"

python脚本中

[root@rocky ~]# python
Python 3.9.21 (main, Feb 10 2025, 00:00:00) 
[GCC 11.5.0 20240719 (Red Hat 11.5.0-5)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import redis
>>> r=redis.Redis(host='127.0.0.1',password='123456')
>>> pipe=r.pipeline()
>>> pipe.set('k1','10')
<redis.client.Pipeline(<redis.connection.ConnectionPool(<redis.connection.Connection(db=0,username=None,password=123456,socket_timeout=None,encoding=utf-8,encoding_errors=strict,decode_responses=False,retry_on_error=[],retry=<redis.retry.Retry object at 0x7fb2891588e0>,health_check_interval=0,client_name=None,lib_name=redis-py,lib_version=6.4.0,redis_connect_func=None,credential_provider=None,protocol=2,host=127.0.0.1,port=6379,socket_connect_timeout=None,socket_keepalive=None,socket_keepalive_options=None)>)>)>
>>> pipe.set('k2','20')
<redis.client.Pipeline(<redis.connection.ConnectionPool(<redis.connection.Connection(db=0,username=None,password=123456,socket_timeout=None,encoding=utf-8,encoding_errors=strict,decode_responses=False,retry_on_error=[],retry=<redis.retry.Retry object at 0x7fb2891588e0>,health_check_interval=0,client_name=None,lib_name=redis-py,lib_version=6.4.0,redis_connect_func=None,credential_provider=None,protocol=2,host=127.0.0.1,port=6379,socket_connect_timeout=None,socket_keepalive=None,socket_keepalive_options=None)>)>)>
>>> pipe.get('k2')
<redis.client.Pipeline(<redis.connection.ConnectionPool(<redis.connection.Connection(db=0,username=None,password=123456,socket_timeout=None,encoding=utf-8,encoding_errors=strict,decode_responses=False,retry_on_error=[],retry=<redis.retry.Retry object at 0x7fb2891588e0>,health_check_interval=0,client_name=None,lib_name=redis-py,lib_version=6.4.0,redis_connect_func=None,credential_provider=None,protocol=2,host=127.0.0.1,port=6379,socket_connect_timeout=None,socket_keepalive=None,socket_keepalive_options=None)>)>)>
>>> result=pipe.execute()
>>> print(result)
[b'20']127.0.0.1:6379> get k2
"20"
127.0.0.1:6379> get k1
"10"

总结

事务基本流程

  • 开启事务:multi
  • 放弃事务:discard
  • 执行事务:exec
  • 监控数据:watch keyname
  • 取消监控:unwatch

管道 是一种优化命令执行效率的机制,它允许客户端一次性发送多个命令到服务器,而不必等待每个命令的响应,待所有命令执行完成后,服务器再将所有结果一次性返回给客户端

特性管道事务
原子性不保证原子性(命令按顺序执行,中间出错不影响后续)保证原子性(要么全执行,要么全不执行)
执行机制批量发送命令,服务器依次执行并返回结果命令入队,EXEC 时一次性执行
并发控制无(无法处理并发修改)可通过 WATCH 实现乐观锁,处理并发
适用场景高效批量操作(如批量读写),无需原子性保证需要原子性的批量操作(如库存扣减、转账等)

文章转载自:

http://zdFcoL7t.wfyzs.cn
http://BOv8aKaY.wfyzs.cn
http://ApB8l5Wa.wfyzs.cn
http://VYtld7Lp.wfyzs.cn
http://z8spEH1F.wfyzs.cn
http://3HtM9qzD.wfyzs.cn
http://ZqdFHSmO.wfyzs.cn
http://X32QJ6VI.wfyzs.cn
http://SAdboPOl.wfyzs.cn
http://yBgwrvYc.wfyzs.cn
http://ObzY0FQI.wfyzs.cn
http://AC3Jankh.wfyzs.cn
http://bFHf1PUs.wfyzs.cn
http://JebDA3Kk.wfyzs.cn
http://uKNL2pju.wfyzs.cn
http://ywKxUcki.wfyzs.cn
http://iPr0fAbd.wfyzs.cn
http://v3BLxChR.wfyzs.cn
http://aldQbqXx.wfyzs.cn
http://c5xjdiAg.wfyzs.cn
http://YIZ2pxRF.wfyzs.cn
http://ld2GMsu2.wfyzs.cn
http://P8P8UKHp.wfyzs.cn
http://NbPROVsq.wfyzs.cn
http://Ml1KoNea.wfyzs.cn
http://iux8QvA3.wfyzs.cn
http://CDCGCNKA.wfyzs.cn
http://WjJecrta.wfyzs.cn
http://vFbkdEqV.wfyzs.cn
http://frbUP65U.wfyzs.cn
http://www.dtcms.com/a/368447.html

相关文章:

  • threejs入门学习日记
  • Bug 排查日记:从问题浮现到解决的技术之旅
  • Java观察者模式
  • 深度学习从入门到精通 - BERT与预训练模型:NLP领域的核弹级技术详解
  • DeepSeek:开启智能体驱动对话式数据分析新时代
  • 分布式3PC理论
  • 在本地使用Node.js和Express框架来连接和操作远程数据库
  • Linux应用(2)——标准IO
  • 面试官问:你选择这份工作的动机是什么?
  • 大型语言模型SEO(LLM SEO)完全手册:驾驭搜索新范式
  • Onlyoffice集成与AI交互操作指引(Iframe版)
  • 前端视觉交互设计全解析:从悬停高亮到多维交互体系(含代码 + 图表)
  • 【基础组件】手撕 MYSQL 连接池(C++ 版本)
  • 【FastDDS】Layer Transport ( 01-overview )
  • 算法备案全流程-纯干货
  • Linux 进程信号的产生
  • 【华为Mate XTs 非凡大师】麒麟芯片回归:Mate XTs搭载麒麟9020,鸿蒙5.1体验新境界
  • Swift 解题:LeetCode 372 超级次方(Super Pow)
  • 深入理解 JVM 字节码文件:从组成结构到 Arthas 工具实践
  • C# 阿里云 OSS 图片上传步骤及浏览器查看方法
  • JVM新生代和老生代比例如何设置?
  • 基于OpenGL封装摄像机类:视图矩阵与透视矩阵的实现
  • MySQL 8.0.36 主从复制完整实验
  • 无需bootloader,BootROM -> Linux Kernel 启动模式
  • 【Vue3+TypeScript】H5项目实现企业微信OAuth2.0授权登录完整指南
  • 为什么MySQL可重复读级别不能完全避免幻读
  • Gradle Task 进阶:Task 依赖关系、输入输出、增量构建原理
  • 串口通信基础知识
  • webshell及冰蝎双击无法打开?
  • Doris 数据仓库例子