Redis事务

首先回顾一下MySql事务:

原子性,一致性,持久性,隔离性

下面看redis:

Redis事务特性

  • 是否存在原子性?

这个特性存在争议,Redis没有回滚机制,多个操作批量执行,不能做到"⼀个失败就恢复到初始状态"

mysql的原子性:要么全部执行成功,要么都不执行

  • 不存在一致性:

redis不涉及"约束". 也没有回滚.MySQL的⼀致性体现的是运⾏事务前和运⾏后,结果都是合理有效的,不会出现中间⾮法状态

  • 不存在持久性:

是保存在内存的.是否开启持久化,是redis-server⾃⼰的事情,和事务⽆关

  • 不存在隔离性:

redis单线程处理请求

Redis 事务本质上是在服务器上搞了⼀个"事务队列".每次客⼾端在事务中进⾏⼀个操作,都会把命令先发给服务器,放到"事务队列"中(但是并不会⽴即执⾏)

⽽是会在真正收到EXEC命令之后,才真正执⾏队列中的所有操作.

主要意义:

就是为了"打包",避免了其它客户端的命令插队插到中间

举个例子,我去烤串,我先点了几串,但是我朋友还没来,我告诉老板等一会再考,过了一会,朋友来了,又加了几个菜,我告诉老板,开始烤,此时我先点的菜和朋友后点的菜是一起烤的,这中间,是没有被插队的,这个不被插队,不是先抢占位置,而是先让出位置.

MULTI

开启⼀个事务.执⾏成功返回OK

EXEC

真正执行事务

每次添加⼀个操作,都会提⽰"QUEUED",说明命令已经进⼊客⼾端的队列了

真正执⾏EXEC的时候,客⼾端才会真正把上述操作发送给服务器

DISCARD

放弃当前事务.此时直接清空事务队列.之前的操作都不会真正执⾏到.

WATCH

在执⾏事务的时候,如果某个事务中修改的值,被别的客⼾端修改了,此时就容易出现数据不⼀致的问 题.

必须搭配事务使用,在multi之前

举例看一下:

客户端1:

客户端2:

最后客户端1,执行:

那么,此时key的值为多少?

从时间上看,先发送1,后发送2,结果是1,真正执行exec才会执行,1变成实际上更晚执行

这个时候,就会引起歧义

因此,即使不保证严格的隔离性,⾄少也要告诉⽤⼾,当前的操作可能存在⻛险

watch命令就是⽤来解决这个问题的

watch在该客⼾端上监控⼀组具体的key

当开启事务的时候,如果对watch的key进⾏修改,就会记录当前key的"版本号".(版本号是个简单 的整数,每次修改都会使版本变⼤.服务器来维护每个key的版本号情况).

在真正提交事务的时候,如果发现当前服务器上的key的版本号已经超过了事务开始时的版本号,就 会让事务执⾏失败.(事务中的所有操作都不执⾏).

此时,再按照上述的步骤执行,返回nil,说明明事务已经被取消了.这次提交的所有命令都没有执⾏

UNWATCH

取消对key的监控. 相当于WATCH的逆操作.此处不做演⽰

什么时候要使用Redis事务呢?

把多个操作打包进行,使用事务比较合适

比如说超卖现象:

放货3000,实际上3001个人下单成功,就超卖了

看一个典型的写法:

如果不加上任何限制,就可能存在线程安全问题

之前在多线程中,是通过加锁来避免插队的,在redis中就可以直接使用事务.

redis服务器收到执行事务操作的时候才会真正执行.

第二个客户端的执行事务命名发过来之后,服务器才真正执行第二个事务的内容,此时第一个事务已经运行了,那么第二个事务得到的个数就是第一个事务自减后的结果

此时,没加锁也可以解决超卖问题

补充:

乐观锁和悲观锁

不是具体的一个锁,而是一类

乐观锁:在加锁之前,就有一个预期,锁冲突概率低

悲观锁:锁冲突概率高

watch就是乐观锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值