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

Redis中的事务机制

Redis中的事务机制

概述。

事务表示一组动作,要么全部执行,要么全部不执行。例子如下。
Redis提供了简单的事务功能,讲一组需要一起执行的命令放到multi和exec两个命令之间。multi命令代表事务开始,exec命令代表事务结束,如果要停止事务的执行,可以使用discard命令代替exec命令即可。它们之间的命令是原子执行的

例子

例如在社交网站上用户A关注了用户B,那么需要在用户A的关注表中加入用户B,并且在用户B的粉丝表中添加用户A,这两个行为要么全部执行,要么全部不执行,否则会出现数据不一致的情况

例如下面代码实现了用户关注问题

127.0.0.1:6379> SADD u:a:follow ub
QUEUED
127.0.0.1:6379> SADD u:b:fans ua
QUEUED

可以看到SADD命令此时的返回结果是QUEUED,代表命令并没有真正执行,而是暂时保存在Redis中的一个缓存队列(所以discard也只是丢弃这个缓存队列中的未执行命令,并不会回滚已经操作过的数据,这一点要和关系型数据库的Rollback操作区分开)。如果此时另一个客户端执行下方代码,返回结果应该是0

127.0.0.1:6379> SISMEMBER u:a:follow ub
(integer) 0

只有当exec执行后,用户A关注用户B的行为才算完成,如下所示exec返回的两个结果对应SADD命令

127.0.0.1:6379> multi
OK
127.0.0.1:6379> SADD u:a:follow ub
QUEUED
127.0.0.1:6379> SADD u:b:fans ua
QUEUED
127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 1

另一个客户端:

127.0.0.1:6379> SISMEMBER u:a:follow ub
(integer) 0
127.0.0.1:6379> SISMEMBER u:a:follow ub
(integer) 1

错误处理机制

如果事务中的命令出现错误,Redis的处理机制也不尽相同

1.命令错误

例如下面操作将set写成了SETT,属于语法错误,会造成整个事务无法执行,

127.0.0.1:6379> set txkey hello
OK
127.0.0.1:6379> set txcount 100
OK
127.0.0.1:6379> mget txkey txcount
1) "hello"
2) "100"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> sett txkey world
(error) ERR unknown command `sett`, with args beginning with: `txkey`, `world`,
127.0.0.1:6379> incr txcount
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> mget txkey txcount
1) "hello"
2) "100"

2.运行时错误

例如用户B在添加粉丝列表时,误把SADD命令(针对集合)写成了ZADD命令(针对有序集合),这种就是运行时命令,因为语法时正确的:

127.0.0.1:6379> SADD u:b:fans ua
(integer) 1
127.0.0.1:6379> multi
OK
127.0.0.1:6379> SADD u:c:follow ub
QUEUED
127.0.0.1:6379> ZADD u:b:fans 1 uc
QUEUED
127.0.0.1:6379> exec
1) (integer) 1
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> sismember u:c:follow ub
(integer) 1

可以看到Redis并不支持回滚功能,SADD u:c:follow ub命令已经执行成功,开发人员需要自己修复这类问题。

3.WATCH机制

有些应用场景需要在事务之前,确保事务中的key没有key没有被其他客户端修改过,才执行事务,否则不执行(类似乐观锁)。Redis提供了watch命令来解决这类问题。
客户端1

127.0.0.1:6379> set testwatch java
OK
127.0.0.1:6379> watch testwatch
OK
127.0.0.1:6379> multi
OK

客户端2

127.0.0.1:6379> get testwatch
"java"
127.0.0.1:6379> append testwatch python
(integer) 10

客户端1继续:

127.0.0.1:6379> append testwatch jedis
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get testwatch
"javapython"

可以看到客户端1在执行multi之前执行了watch命令,客户端2在客户端1执行exec之前修改了key值,造成可客户端1事务没有执行(exec结果为nil)

Pipeline和事务的区别

  • 1.pipeline是客户端的行为,对于服务器来说是透明的,可以认为服务器无法区分客户端发送来的查询命令是以普通命令的形式还是以pipeline的形式发送到服务器的;
  • 2.而事务则是实现在服务器端的行为,用户执行MULTI命令时,服务器会将对应这个用户的客户端对象设置为一个特殊的状态,在这个状态下后续用户执行管的查询命令不会被真的执行,而是被服务器缓存起来,直到用户执行EXEC命令为止,服务器会将这个用户对应的客户端对象中缓存的命令按照提交的顺序依次执行
  • 3.应用pipeline可以提高服务器的吞吐能力,并提高Redis处理查询请求的能力。但是这里存在一个问题,当通过pipeline提交的查询命令数据较少,可以被内核缓冲区所容纳时,Redis可以保证这些命令执行的原子性。然而一旦数据量过大,超过了内核缓冲区的接收大小,那么命令的执行将会被打断,原子性也就无法得到保证。因此pipeline只是一种提升服务器吞吐能力的机制,如果想要命令以事务的方式原子性地被执行,还是需要事务机制,或者使用更高级的脚本功能以及模块功能
  • 4.可以将事务和pipeline结合起来使用,减少事务地命令在网络上的传输时间,将多次网络IO缩减为一次网络IO.
  • Redis提供了简单的事务,之所以说它简单,主要时因为它不支持事务中的回滚特性,同时无法实现命令之间的逻辑关系计算,当然也体现了Redis的"keep it simple"的特性

Lua脚本

Redis在2.6推出了脚本功能,允许开发者使用Lua语言编写脚本传到Redis中执行,使用脚本的好处如下:

  • 1.减少网络开销:本来5次网络请求的操作,可以用一个请求完成,原先5次请求的逻辑放在Redis服务器上完成,使用脚本,减少了网络往返时延,跟管道类似
  • 2.源自操作:Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入,管道不是原子的,redis的批量操作命令(类似mset)是原子的
  • 3.替代redis的事务功能:redis自带的事务功能很鸡肋,而redis的lua脚本几乎实现了常规的事务功能,官方推荐如果要使用redis的事务功能可以用redis lua替代
    A Redis script is transactional by definition, so everything you can do with a Redis transaction, you can also do with a script,and usually the script will be both simpler and faster.
http://www.lryc.cn/news/325784.html

相关文章:

  • 从零到一构建短链接系统(八)
  • 缺省和重载。引用——初识c++
  • java常用IO流功能——字符流和缓冲流概述
  • Python中模块的定义、用法
  • 【vscode 常用扩展插件】
  • Retelling|Facebook2
  • 读3dsr代码①测试
  • Vant Weapp小程序 van-uploader 文件上传点击无反应,删除无反应
  • 【力扣】55.跳跃游戏、45.跳跃游戏Ⅱ
  • 038—pandas 重采样线性插补
  • 智慧工地源码 数字孪生可视化大屏 工地管理平台系统源码 多端展示(PC端、手机端、平板端)
  • 深度学习Top10算法之深度神经网络DNN
  • 【智能算法】海马优化算法(SHO)原理及实现
  • AI大模型学习的伦理与社会影响
  • 记录些LangChain相关的知识
  • C语言例4-7:格式字符f的使用例子
  • [蓝桥杯 2019 省 A] 修改数组
  • Git基础(25):Cherry Pick合并指定commit id的提交
  • C语言结构体之位段
  • 2016年认证杯SPSSPRO杯数学建模D题(第二阶段)NBA是否有必要设立四分线全过程文档及程序
  • 登录校验解决方案JWT
  • Flutter开发进阶之瞧瞧BuildOwner
  • 大量免费工具使用(提供api接口)
  • 网络探测工具Nmap介绍
  • 20240319-2-机器学习基础面试题
  • 0202矩阵的运算-矩阵及其运算-线性代数
  • python中的__dict__
  • 数学分析复习:无穷乘积
  • 02 React 组件使用
  • 你就是上帝