Redis——Redis事务性原理

编程入门 行业动态 更新时间:2024-10-27 07:25:26

Redis——Redis事务性<a href=https://www.elefans.com/category/jswz/34/1770123.html style=原理"/>

Redis——Redis事务性原理

摘要

本文主要介绍redis事务相关的原理与实战。很多读者看到网络说redis是么有事务处理,但是这个是错误。redis同样的有事务特性。这个和很多人理解的不一样。

一、java传统的事务的处理

事务指的是提供一种将多个命令打包,一次性按顺序地执行的机制,并且保证服务器只有在执行完事务中的所有命令后,才会继续处理此客户端的其他命令。事务也是其他关系型数据库所必备的基础功能,以支付的场景为例,正常情况下只有正常消费完成之后,才会减去账户余额。但如果没有事务的保障,可能会发生消费失败了,但依旧会把账户的余额给扣减了,我想这种情况应该任何人都无法接受吧?所以事务是数据库中一项非常重要的基础功能。

事务在其他语言中,一般分为以下三个阶段:

  • 开启事务——Begin Transaction
  • 执行业务代码,提交事务——Commit Transaction
  • 业务处理中出现异常,回滚事务——Rollback Transaction
// 开启事务
begin();
try {//......// 提交事务commit();
} catch(Exception e) {// 回滚事务rollback();
}

二、Redis中的事务处理

  • 开启事务
  • 命令入列
  • 执行事务/放弃事务

其中,开启事务使用 multi 命令,事务执行使用 exec 命令,放弃事务使用 discard 命令。

如果能够保证redis命令不会出错。对于redis的事务来说就是原子性质的。

开启事务:multi 命令用于开启事务,multi 命令可以让客户端从非事务模式状态,变为事务模式状态,注意:multi 命令不能嵌套使用,如果已经开启了事务的情况下,再执行 multi 命令,会提示如下错误:如下图所示:

当客户端是非事务状态时,使用 multi 命令,客户端会返回结果 OK,如果客户端已经是事务状态,再执行 multi 命令会 multi 命令不能嵌套的错误,但不会终止客户端为事务的状态,如下图所示:

命令入列:客户端进入事务状态之后,执行的所有常规 Redis 操作命令(非触发事务执行或放弃和导致入列异常的命令)会依次入列,命令入列成功后会返回 QUEUED,

注意:命令会按照先进先出(FIFO)的顺序出入列,也就是说事务会按照命令的入列顺序,从前往后依次执行。

执行事务/放弃事务:执行事务的命令是 exec,放弃事务的命令是 discard。

三、redis中的事务错误和回滚

事务执行中的错误分为以下三类:

  • 执行时才会出现的错误(简称:执行时错误);
  • 入列时错误,不会终止整个事务;
  • 入列时错误,会终止整个事务。

执行时错误

从以上结果可以看出,即使事务队列中某个命令在执行期间发生了错误,事务也会继续执行,直到事务队列中所有命令执行完成。

入列错误不会导致事务结束

可以看出,重复执行 multi 会导致入列错误,但不会终止事务,最终查询的结果是事务执行成功了。除了重复执行 multi 命令,还有在事务状态下执行 watch 也是同样的效果,

入列错误导致事务结束

为什么不支持事务回滚?

这里不支持事务回滚,指的是不支持运行时错误的事务回滚。作者不支持事务回滚的原因有以下两个:

  • 他认为 Redis 事务的执行时,错误通常都是编程错误造成的,这种错误通常只会出现在开发环境中,而很少会在实际的生产环境中出现,所以他认为没有必要为 Redis 开发事务回滚功能;
  • 不支持事务回滚是因为这种复杂的功能和 Redis 追求的简单高效的设计主旨不符合。

四、Redis的监控

watch 命令用于客户端并发情况下,为事务提供一个乐观锁(CAS,Check And Set),也就是可以用 watch 命令来监控一个或多个变量,如果在事务的过程中,某个监控项被修改了,那么整个事务就会终止执行

watch 示例代码如下:> watch k
OK
> multi
OK
> set k v2
QUEUED
> exec
(nil)
> get k
"v"

注意:以上事务在执行期间,也就是开启事务(multi)之后,执行事务(exec)之前,模拟多客户端并发操作了变量 k 的值,这个时候再去执行事务,才会出现如上结果,exec 执行的结果为 nil。可以看出,当执行 exec 返回的结果是 nil 时,表示 watch 监控的对象在事务执行的过程中被修改了。从 get k 的结果也可以印证,因为事务中设置的值 set k v2 未正常执行。

注意: watch 命令只能在客户端开启事务之前执行,在事务中执行 watch 命令会引发错误,但不会造成整个事务失败,如下代码所示:

unwatch 命令用于清除所有之前监控的所有对象(键值对)。可以看出,即使在事务的执行过程中,k 值被修改了,因为调用了 unwatch 命令,整个事务依然会顺利执行。

五、redis事务代码实战

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;public class TransactionExample {public static void main(String[] args) {// 创建 Redis 连接Jedis jedis = new Jedis("xxx.xxx.xxx.xxx", 6379);// 设置 Redis 密码jedis.auth("xxx");// 设置键值jedis.set("k", "v");// 开启监视 watchjedis.watch("k");// 开始事务Transaction tx = jedis.multi();// 命令入列tx.set("k", "v2");// 执行事务tx.exec();System.out.println(jedis.get("k"));jedis.close();}
}

博文参考

更多推荐

Redis——Redis事务性原理

本文发布于:2023-06-18 08:54:38,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/768621.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:原理   Redis

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!