欢迎访问本站!

首页头条正文

usdt充币教程(www.caibao.it):不能回滚的Redis事务还能用吗

admin2021-03-0819

USDT自动充值

菜宝钱包(caibao.it)是使用TRC-20协议的Usdt第三方支付平台,Usdt收款平台、Usdt自动充提平台、usdt跑分平台。免费提供入金通道、Usdt钱包支付接口、Usdt自动充值接口、Usdt无需实名寄售回收。菜宝Usdt钱包一键生成Usdt钱包、一键调用API接口、一键无实名出售Usdt。

原题目:不能回滚的Redis事务还能用吗

前言

事务是关系型数据库的特征之一,那么作为 Nosql 的代表 Redis 中有事务吗?若是有,那么 Redis 当中的事务又是否具备关系型数据库的 ACID 四大特征呢?

Redis 有事务吗

这个谜底可能会令很多人感应意外, Redis 当中是存在“事务”的。这里我把 Redis 的事务带了引号,缘故原由在后面剖析。

Redis 当中的单个下令都是原子操作,然则若是我们需要把多个下令组合操作又需要保证数据的一致性时,就可以考试使用 Redis 提供的事务(或者使用前面先容的 Lua 剧本)。

Redis 当中,通过下面 4 个下令来实现事务:

Redis 的事务主要分为以下 3 步:

  1. 开启事务之后执行的下令都市被放入一个行列,若是乐成之后会牢固返回 QUEUED 。
  2. 执行下令 exec 提交事务之后, Redis 会依次执行行列内里的下令,并依次返回所有下令效果(若是想要放弃事务,可以执行 discard 下令)。

接下来让我们依次执行以下下令来体会一下 Redis 当中的事务:

multi //开启事务

set name lonely_wolf //设置 name,此时 Redis 会将下令放入行列

set age 18 //设值 age,此时 Redis 会将下令放入行列

get name //获取 name,此时 Redis 会将下令放入行列

exec //提交事务,此时会依次执行行列里的下令,并依次返回效果

执行完成之后获得如下效果:

Redis 事务实现原理

Redis 中每个客户端都有纪录当前客户端的事务状态 multiState ,下面就是一个客户端 client 的数据结构界说:

typedef struct client {

uint64_t id;//客户端唯一 id

multiState mstate; //MULTI 和 EXEC 状态(即事务状态)

//...省略其他属性

} client;

multiState 数据结构界说如下:

typedef struct multiState {

multiCmd *commands;//存储下令的 FIFO 行列

int count;//下令总数

//...省略了其他属性

} multiState;

multiCmd 是一个行列,用来吸收并存储开启事务之后发送的下令,其数据结构界说如下:

typedef struct multiCmd {

robj **argv;//用来存储参数的数组

int argc;//参数的数目

struct redisCommand *cmd;//下令指针

} multiCmd;

我们以上面事务的示例截图中事务为例,可以获得如下所示的一个简图:

Redis 事务 ACID 特征

传统的关系型数据库中,一个事务一样平常都具有 ACID 特征。那么现在就让我们来剖析一下 Redis 是否也知足这 ACID 四大特征。

A - 原子性

在讨论事务的原子性之前,我们先来看 2 个例子。

  • 模拟事务在执行下令前发生异常。依次执行以下下令:
multi //开启事务

set name lonely_wolf //设置 name,此时 Redis 会将下令放入行列

get //执行一个不完成的下令,此时会报错

exec //在发生异常后提交事务

最终获得了如下图所示的效果,我们可以看到,当下令入队的时刻报错时,事务已经被取消了:

  • 模拟事务在执行下令前发生异常。依次执行以下下令:
flushall //为了防止影响,先清空数据库

multi //开启事务

set name lonely_wolf //设置 name,此时 Redis 会将下令放入行列

incr name //这个下令只能用于 value 为整数的字符串工具,此时执行会报错

exec //提交事务,此时在执行第一条下令乐成,执行第二条下令失败

get name //获取 name 的值

,

Usdt第三方支付接口

菜宝钱包(www.caibao.it)是使用TRC-20协议的Usdt第三方支付平台,Usdt收款平台、Usdt自动充提平台、usdt跑分平台。免费提供入金通道、Usdt钱包支付接口、Usdt自动充值接口、Usdt无需实名寄售回收。菜宝Usdt钱包一键生成Usdt钱包、一键调用API接口、一键无实名出售Usdt。

,

最终获得了如下图所示的效果,我们可以看到,当执行事务报错的时刻,之前已经乐成的下令并没有被回滚,也就是说 在执行事务的时刻某一个下令失败了,并不会影响其他下令的执行,即 Redis 的事务并不会回滚

Redis 中的事务为什么不会滚

这个问题的谜底在 Redis 官网中给出了明确的注释:

总结起来主要就是 3 个缘故原由:

  • Redis 作者以为发生事务回滚的缘故原由大部分都是程序错误导致,这种情形一样平常发生在开发和测试阶段,而生产环境很少泛起。
  • 对于逻辑性错误,好比原本应该把一个数加 1 ,然则程序逻辑写成了加 2 ,那么这种错误也是无法通过事务回滚来举行解决的。
  • Redis 追求的是简朴高效,而传统事务的实现相对对照复杂,这和 Redis 的设计头脑相违反。
C - 一致性

一致性指的就是事务执行前后的数据相符数据库的界说和要求。这一点 Redis 中的事务是相符要求的,上面讲述原子性的时刻已经提到,不论是发生语法错误照样运行时错误,错误的下令均不会被执行。

I - 隔离性

事务中的所有下令都市按顺序执行,在执行 Redis 事务的过程中,另一个客户端发出的请求不可能被服务,这保证了下令是作为单独的自力操作执行的。以是 Redis 当中的事务是相符隔离性要求的。

D - 持久性

若是 Redis 当中没有被开启持久化,那么就是纯内存运行的,一旦重启,所有数据都市丢失,此时可以以为 Redis 不具备事务的持久性;而若是 Redis 开启了持久化,那么可以以为 Redis 在特定条件下是具备持久性的。

watch 下令

上面我们讲述 Redis 中事务时,提到的的常用下令另有一个 watch 下令,这个又是做什么用的呢?我们照样先来看一个例子。

首先打开一个客户端一,依次执行以下下令:

flushall //清空数据库

multi //开启事务

get name //获取 name,此时正常返回 nil

set name lonely_wolf //设置 name

get name //获取 name,此时正常应该返回 lonely_wolf

获得如下效果图:

这时刻我们先不执行事务,打开另一个客户端二,来执行一个下令 set name zhangsan :

客户端二执行乐成了,这时刻再返回到客户端一执行 exec 下令:

可以发现,第一句话返回了 zhangsan 。也就是说, name 这个 key 值在入队之后到 exec 之前发生了转变,一旦发生这种情形,可能会引起很严重的问题,以是在关系型数据库可以通过锁来解决这种问题,那么 Redis 当中试若何解决的呢?

是的,在 Redis 当中就是通过 watch 下令来处置这种场景的。

watch 下令的作用

watch 下令可以为 Redis 事务提供 CAS 乐观锁行为,它可以在 exec 下令执行之前,监视随便 key 值的转变,也就是说当多个线程更新同一个 key 值的时刻,会跟原值做对照,一旦发现它被修悔改,则拒绝执行下令,并且会返回 nil 给客户端。

下面照样让我们通过一个示例来演示一下。

打开一个客户端一,依次执行如下下令:

flushall //清空数据库

watch name //监视 name

multi //开启事务

set name lonely_wolf //设置 name

set age 18 // 设置 age

get name //获取 name

get age //获取 age

执行之后获得如下效果图:

这时刻再打开一个客户端二,执行 set name zhangsan 下令:

然后再回到客户端一执行 exec 下令。这时刻会发现直接返回了 nil ,也就是事务中所有的下令都没有被执行(即:只要检测到一个 key 值被修悔改,那么整个事务都不会被执行):

watch 原理剖析

下面是一个 Redis 服务的数据结构界说:

typedef struct redisDb {

dict *watched_keys; //被 watch 下令监视的 key

int id; //Database ID

//...省略了其他属性

} redisDb;

可以看到, redisDb 中的 watched_keys 存储了一个字典,这个字典当中的 key 存的就是被监视的 key ,然后字典的值存的就是客户端 id 。然后每个客户端另有一个符号属性 CLIENT_DIRTY_CAS ,一旦我们执行了一些如 set , sadd 等能修改 key 值对应 value 的下令,那么客户端的 CLIENT_DIRTY_CAS 符号属性将会被修改,后面执行事务提交下令 exec 时发现客户端的符号属性被修悔改(乐观锁的体现),则会拒绝执行事务。

总结

网友评论