【征服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的问题,我们后面再介绍。

相关推荐

  1. 征服redis9】快速征服lua脚本

    2024-01-17 12:32:03       35 阅读
  2. Redis系列——Lua脚本和redis事务应用

    2024-01-17 12:32:03       30 阅读
  3. Redis Pipeline(管道)事务区分

    2024-01-17 12:32:03       23 阅读
  4. 关于Redis事务

    2024-01-17 12:32:03       34 阅读
  5. Redis事务

    2024-01-17 12:32:03       19 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-17 12:32:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-17 12:32:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-17 12:32:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-17 12:32:03       20 阅读

热门阅读

  1. 机器学习之集成学习 XGBoost 附代码解析

    2024-01-17 12:32:03       34 阅读
  2. 数据分析平台哪个好

    2024-01-17 12:32:03       36 阅读
  3. 开箱即用之MyBatisPlus XML 自定义分页

    2024-01-17 12:32:03       32 阅读
  4. 记一次Log记录大对象导致的CPU异常和磁盘打满

    2024-01-17 12:32:03       35 阅读
  5. PHP 字符串面试题

    2024-01-17 12:32:03       33 阅读
  6. 什么是池化层?

    2024-01-17 12:32:03       33 阅读
  7. 2024华数杯国际数学建模A题思路模型详解

    2024-01-17 12:32:03       31 阅读
  8. 设计模式——原型模式

    2024-01-17 12:32:03       32 阅读
  9. 正则表达式 (用于灵活匹配文本的表达式)

    2024-01-17 12:32:03       34 阅读
  10. 自定义shell工具函数之pull_image()

    2024-01-17 12:32:03       30 阅读