【征服redis2】redis的事务与lua

1.redis事务介绍

在前面我们介绍了redis的几种典型数据结构和应用,本文我们来看一下redis的事务问题。事务也是数据库的重要主题,熟悉关系型数据库的读者应该对事务比较了解,简单地说,事务表示一组动作,要么全部执行,要么全部不执行。例如在社交网站上用户 A关注了用户B,那么需要在用户A的关注表中加入用户B,并且在用户B的粉丝表中添加用户A,这两个行为要么全部执行,要么全部不执行,否则会出现数据不一致的情况。

Redis提供了简单的事务功能,将一组需要一起执行的命令放到 multi和exec两个命令之间。multi命令代表事务开始,exec命令代表事务 结束,它们之间的命令是原子顺序执行的,例如下面操作实现了上述用户关注问题。

复制代码
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> sadd user:a:follow user:b
QUEUED
127.0.0.1:6379(TX)> sadd user:b:fans user:a
QUEUED

可以看到sadd命令此时的返回结果是QUEUED,代表命令并没有真 正执行,而是暂时保存在Redis中。如果此时另一个客户端执行 sismember user:a:follow user:b返回结果应该为0。

复制代码
127.0.0.1:6379> sismember user:a:follow user:b
(integer) 0

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

复制代码
第一个终端:
127.0.0.1:6379(TX)> exec
1) (integer) 1
2) (integer) 1

第二个终端:
127.0.0.1:6379> sismember user:a:follow user:b
(integer) 1

如果要停止事务的执行,可以使用discard命令代替exec命令即可。

2 事务出错的处理

如果事务中的命令出现错误,Redis的处理机制也不一样。

情况1.命令错误

例如下面操作错将set写成了sett,属于语法错误,会造成整个事务无法执行,key和counter的值未发生变化。

比如说我们按照下面的方式来执行redis事务:

127.0.0.1:6379> mget key counter

  1. "2"

  2. "100"

127.0.0.1:6379>

127.0.0.1:6379> multi

OK

127.0.0.1:6379(TX)> sett key world

(error) ERR unknown command `sett`, with args beginning with: `key`, `world`,

127.0.0.1:6379(TX)> incr counter

QUEUED

127.0.0.1:6379(TX)> exec

(error) EXECABORT Transaction discarded because of previous errors.

127.0.0.1:6379> mget key counter

  1. "2"

  2. "100"

127.0.0.1:6379>

可以看到最后的counter并没有发生变化。

情况2.运行时错误

例如用户B在添加粉丝列表时,误把sadd命令写成了zadd命令,这种就是运行时命令,因为语法是正确的,redis是无法察觉到这种错误的。例如:

127.0.0.1:6379> multi

OK

127.0.0.1:6379(TX)> sadd user:a:follow user:b

QUEUED

127.0.0.1:6379(TX)> zadd user:b:fans 1 user:a

QUEUED

127.0.0.1:6379(TX)> exec

  1. (integer) 0

  2. (error) WRONGTYPE Operation against a key holding the wrong kind of value

127.0.0.1:6379> sismember user:a:follow user:b

(integer) 1

127.0.0.1:6379>

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

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

可以看到"客户端-1"在执行multi之前执行了watch命令,"客户 端-2"在"客户端-1"执行exec之前修改了key值,造成事务没有执行(exec 结果为nil),整个代码如下所示:

客户端1:

127.0.0.1:6379> set key "java"

OK

127.0.0.1:6379> watch key

OK

127.0.0.1:6379> multi

OK

此时客户端2执行:

append key python

然后回到客户端1:

127.0.0.1:6379(TX)> append key jedis

QUEUED

127.0.0.1:6379(TX)> exec

(nil)

127.0.0.1:6379> get key

"javapython"

127.0.0.1:6379>

Redis提供了简单的事务,之所以说它简单,主要是因为它不支持 事务中的回滚特性,同时无法实现命令之间的逻辑关系计算,当然也体现了Redis的"keep it simple"的特性,下一小节介绍的Lua脚本同样可以实现事务的相关功能,但是功能要强大很多。

lua的问题,我们后面再介绍。

相关推荐
梦Arrebol29 分钟前
Redis 内容及相关实验
数据库·redis
大模型码小白1 小时前
Spring AI Tool 实现自然语言操作 MySQL 数据库详解
服务器·开发语言·数据库·人工智能·python·mysql·spring
DBA大董3 小时前
TDengine3.0 DBA常用的运维命令和SQL2
运维·数据库·时序数据库·dba·tdengine
ManageEngineITSM3 小时前
什么是CMDB?配置管理数据库的定义、作用与建设方法一文讲清
大数据·数据库·人工智能·资产管理·变更管理
IvorySQL3 小时前
PostgreSQL 日报|PG19 外键快速路径隐患已修复(8 月 23 日)
数据库·postgresql
Elastic 中国社区官方博客4 小时前
OpenTelemetry Java 扩展:无需分叉 agent 即可自定义追踪
java·大数据·运维·开发语言·数据库·人工智能·elasticsearch
只爱喝胡辣汤4 小时前
Redis Intset(整数集合)技术文档
redis
01传说4 小时前
redis开机自启脚本
数据库·redis·缓存
这个DBA有点耶4 小时前
数据库运维的“自动驾驶”:KES-Operator如何把DBA经验编码为软件
数据库·dba·自动化运维