不支持原子性的-Redis-事务也叫事务吗?,Java开发自学教程

Redis 在形式上看起来也差不多,分为三个阶段

  1. 开启事务(multi)
  2. 命令入队(业务操作)
  3. 执行事务(exec)或取消事务(discard)

multi
OK
incr star
QUEUED
incr star
QUEUED
exec
(integer) 1
(integer) 2

上面的指令演示了一个完整的事务过程,所有的指令在 exec 之前不执行,而是缓存在服务器的一个事务队列中,服务器一旦收到 exec 指令,才开执行整个事务队列,执行完毕后一次性返回所有指令的运行结果。

Redis 事务可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。

可以保证一个队列中,一次性、顺序性、排他性的执行一系列命令(Redis 事务的主要作用其实就是串联多个命令防止别的命令插队)

官方文档是这么说的

事务可以一次执行多个命令, 并且带有以下两个重要的保证:

  • 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行

这个原子操作,和关系型 DB 的原子性不太一样,它不能完全保证原子性,后边会介绍。

Redis 事务的几个命令

MULTI 命令用于开启一个事务,它总是返回 OK 。

MULTI 执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中, 当 EXEC命令被调用时, 所有队列中的命令才会被执行。

另一方面, 通过调用 DISCARD , 客户端可以清空事务队列, 并放弃执行事务。

废话不多说,直接操作起来看结果更好理解~

一帆风顺

正常执行(可以批处理,挺爽,每条操作成功的话都会各取所需,互不影响)

放弃事务(discard 操作表示放弃事务,之前的操作都不算数)

思考个问题:假设我们有个有过期时间的 key,在事务操作中 key 失效了,那执行 exec 的时候会成功吗?

事务中的错误

上边规规矩矩的操作,看着还挺好,可是事务是为解决数据安全操作提出的,我们用 Redis 事务的时候,可能会遇上以下两种错误:

  • 事务在执行 EXEC 之前,入队的命令可能会出错。比如说,命令可能会产生语法错误(参数数量错误,参数名错误等等),或者其他更严重的错误,比如内存不足(如果服务器使用 maxmemory 设置了最大内存限制的话)。
  • 命令可能在 EXEC 调用之后失败。举个例子,事务中的命令可能处理了错误类型的键,比如将列表命令用在了字符串键上面,诸如此类。

Redis 针对如上两种错误采用了不同的处理策略,对于发生在 EXEC 执行之前的错误,服务器会对命令入队失败的情况进行记录,并在客户端调用 EXEC 命令时,拒绝执行并自动放弃这个事务(Redis 2.6.5 之前的做法是检查命令入队所得的返回值:如果命令入队时返回 QUEUED ,那么入队成功;否则,就是入队失败)

对于那些在 EXEC 命令执行之后所产生的错误, 并没有对它们进行特别处理: 即使事务中有某个/某些命令在执行时产生了错误, 事务中的其他命令仍然会继续执行。

全体连坐(某一条操作记录报错的话,exec 后所有操作都不会成功)

冤头债主(示例中 k1 被设置为 String 类型,decr k1 可以放入操作队列中,因为只有在执行的时候才可以判断出语句错误,其他正确的会被正常执行)

为什么 Redis 不支持回滚

如果你有使用关系式数据库的经验,那么 “Redis 在事务失败时不进行回滚,而是继续执行余下的命令”这种做法可能会让你觉得有点奇怪。

以下是官方的自夸

  • Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
  • 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。

有种观点认为 Redis 处理事务的做法会产生 bug , 然而需要注意的是, 在通常情况下, 回滚并不能解决编程错误带来的问题。 举个例子, 如果你本来想通过 INCR 命令将键的值加上 1 , 却不小心加上了 2 , 又或者对错误类型的键执行了 INCR , 回滚是没有办法处理这些情况的。

鉴于没有任何机制能避免程序员自己造成的错误, 并且这类错误通常不会在生产环境中出现, 所以 Redis 选择了更简单、更快速的无回滚方式来处理事务。

带 Watch 的事务

WATCH 命令用于在事务开始之前监视任意数量的键: 当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务将被打断,不再执行, 直接返回失败。

WATCH命令可以被调用多次。 对键的监视从 WATCH 执行之后开始生效, 直到调用 EXEC 为止。

用户还可以在单个 WATCH 命令中监视任意多个键, 就像这样:

redis> WATCH key1 key2 key3
OK

当 EXEC 被调用时, 不管事务是否成功执行, 对所有键的监视都会被取消。另外, 当客户端断开连接时, 该客户端对键的监视也会被取消。

我们看个简单的例子,用 watch 监控我的账号余额(一周100零花钱的我),正常消费

但这个卡,还绑定了我媳妇的支付宝,如果在我消费的时候,她也消费了,会怎么样呢?

犯困的我去楼下 711 买了包烟,买了瓶水,这时候我媳妇在超市直接刷了 100,此时余额不足的我还在挑口香糖来着,,,

这时候我去结账,发现刷卡失败(事务中断),尴尬的一批

你可能没看明白 watch 有啥用,我们再来看下,如果还是同样的场景,我们没有 watch balance ,事务不会失败,储蓄卡成负数,是不不太符合业务呢

使用无参数的 UNWATCH 命令可以手动取消对所有键的监视。 对于一些需要改动多个键的事务,有时候程序需要同时对多个键进行加锁, 然后检查这些键的当前值是否符合程序的要求。 当值达不到要求时, 就可以使用 UNWATCH 命令来取消目前对键的监视, 中途放弃这个事务, 并等待事务的下次尝试。

watch指令,类似乐观锁,事务提交时,如果 key 的值已被别的客户端改变,比如某个 list 已被别的客户端push/pop 过了,整个事务队列都不会被执行。(当然也可以用 Redis 实现分布式锁来保证安全性,属于悲观锁)

通过 watch 命令在事务执行之前监控了多个 keys,倘若在 watch 之后有任何 key 的值发生变化,exec 命令执行的事务都将被放弃,同时返回 Null 应答以通知调用者事务执行失败。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

Java核心架构进阶知识点

面试成功其实都是必然发生的事情,因为在此之前我做足了充分的准备工作,不单单是纯粹的刷题,更多的还会去刷一些Java核心架构进阶知识点,比如:JVM、高并发、多线程、缓存、Spring相关、分布式、微服务、RPC、网络、设计模式、MQ、Redis、MySQL、设计模式、负载均衡、算法、数据结构、kafka、ZK、集群等。而这些也全被整理浓缩到了一份pdf——《Java核心架构进阶知识点整理》,全部都是精华中的精华,本着共赢的心态,好东西自然也是要分享的

image

image

image

内容颇多,篇幅却有限,这就不在过多的介绍了,大家可根据以上截图自行脑补

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

多的介绍了,大家可根据以上截图自行脑补

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-GPQAR9ze-1712802343067)]

  • 24
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值