Redis中的事务什么是事务数据库事务(transaction)事务

什么是 Redis 中的事务

数据库事务(transaction)是访问并可能操作各种数据项的一系列数据库操作。这些操作要么全部执行,要么根本不执行,是不可分割的工作单元。事务由在事务开始和事务结束之间执行的所有数据库操作组成。

事务必须满足所谓的 ACID 属性

1、原子性

事务中的所有操作在数据库中都是不可分割的,要么全部完成,要么全部未执行;

2、一致性

事务的执行将数据从一种状态转换到另一种状态,而不会在事务开始之前和事务结束之后破坏数据库的完整性约束。

有点迷糊,来个栗子

如果name字段是数据库中的唯一属性,事务执行后,涉及到字段的修改,事务执行过程中发生回滚,然后字段变为非唯一。这种情况就是破坏事务的一致性要求。

由于上述事务执行过程中name字段属性的不一致,即数据库的状态从一个状态变成了一个不一致的状态。

上面的栗子是数据库不遵循一致性的表现。

3、隔离

事务隔离要求每个读写事务的对象与其他事务的操作对象是分开的,即事务在提交之前对其他事务是不可见的。

通常使用锁来实现。数据库系统提供了细粒度的锁定策略,允许事务只锁定实体对象的一个​​子集,从而提高事务之间的并发性。

4、耐用性

对于任何已提交的事务,系统必须确保该事务对数据库的更改不会丢失,即使数据库发生故障。

届时,如果某些人为或自然灾害导致数据库机房遭到破坏,如火灾、机房爆炸等,在这种情况下提交的数据可能会丢失。

因此可以理解,持久性保证了事务系统的高可靠性,而不是高可用性。

分析Redis中的事务如何在Redis中使用

Redis 提供 MULTI 和 EXEC 命令来执行事务操作

# 初始化一个值
127.0.0.1:6379> set test-mult-key 100
OK
# 开启事务
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECR test-mult-key

QUEUED
127.0.0.1:6379> DECR test-mult-key
QUEUED
127.0.0.1:6379> DECR test-mult-key
QUEUED
# 提交事务
127.0.0.1:6379> EXEC
1) (integer) 99
2) (integer) 98
3) (integer) 97

从上面的执行过程可以看出,交易的执行可以分为三个步骤

1、使用 MULTI 启动事务;

2、当一个事务启动时,所有后续的命令都不会立即执行,而是会放入一个事务队列,然后返回QUEUED,表示该命令已经入队;

3、 那么在执行EXEC命令时,服务端根据客户端保存的事务队列,以先进先出(FIFO)的方式执行事务队列中的命令:命令先入队的先执行,最后入队的命令最后执行。

Redis 中的事务保证这些属性的原子性

如果命令运行正常,则事务中的原子性得到保证。

如果命令在执行过程中失败了怎么办

关于失败的命令,可以分为以下三种情况

1、命令进入队列时报错

比如执行了一个不存在的命令,或者命令写错了

来个栗子

127.0.0.1:6379> set test-mult-key 100
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECR test-mult-key

QUEUED
# DECR 命令拼写错了
127.0.0.1:6379> DECRR test-mult-key
(error) ERR unknown command `DECRR`, with args beginning with: `test-mult-key`,
127.0.0.1:6379> DECR test-mult-key
QUEUED
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.

可以看到事务中的 DECR 命令拼写错误,写成 DECRR。此时,交易无法执行。执行EXEC时,Redis抛出错误,整个事务的执行被丢弃。

这种情况下,当命令排队时,Redis 会报错并记录错误。至此,我们可以继续提交命令操作。 EXEC 命令执行后,Redis 将拒绝执行所有提交的命令操作,并返回事务失败的结果。这样,事务中的所有命令都不会被再次执行,保证了原子性。

2、执行命令时出错

这种情况下,我们在操作Redis命令时,命令的类型不匹配。

例如:我们对一个值为字符串类型的键执行 DECR 操作。

127.0.0.1:6379> set test-mult-key 100
OK
127.0.0.1:6379> set test-mult-key-string 's100'
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECR test-mult-key
QUEUED
127.0.0.1:6379> DECR test-mult-key
QUEUED
# 对 value 为 string 的,执行 DECR 操作,结果会报错
# 模拟错误的命令
127.0.0.1:6379> DECR test-mult-key-string

图片[1]-Redis中的事务什么是事务数据库事务(transaction)事务-唐朝资源网

QUEUED 127.0.0.1:6379> DECR test-mult-key QUEUED 127.0.0.1:6379> EXEC 1) (integer) 99 2) (integer) 98 3) (error) ERR value is not an integer or out of range 4) (integer) 97

这种情况下,虽然错误的命令会报错,但是正确的命令还是会被执行。

在这种情况下,不能保证命令的原子性。 Redis没有提供事务回滚机制。

3、执行EXEC命令时实例失败

如果 Redis 启用了 AOF 日志记录,那么 AOF 日志中只会记录一些事务操作。

机器实例恢复后,我们可以使用redis-check-aof工具检查AOF日志文件,可以从AOF文件中移除已完成的事务操作。这样,我们使用 AOF 恢复实例后,事务操作就不会再次执行,从而保证了原子性。

所以Redis中事务原子性的总结就是以下几点

1、命令排队时会报错,放弃事务执行以保证原子性;

2、命令排队时不报错,但实际执行命令时报错,原子性不保证;

3、执行 EXEC 命令时实例失败。如果启用AOF日志,可以保证原子性。

看Redis事务中的几个命令

子命令功能说明

丢弃

取消事务,放弃执行事务块中的所有命令

执行

执行事务块中的所有命令

多个

标记一个事务块的开始

不看

取消WATCH命令监控所有按键

WATCH 键 [键 …]

监控一个(或多个)key,如果在事务执行之前key被另一个命令改变,那么事务将被中断

一致性

一致性分析应从以上三点进行

1、命令排队时报错

事务本身不会被执行,可以保证一致性

2、执行命令时出错

错误的命令不会执行,正确的命令会正常执行,不会改变数据库的一致性。

3、执行EXEC命令时实例失败

如果不开启持久化,实例失败重启后,数据没了,数据库一致。

如果使用RDB快照,由于事务执行时不会执行RDB快照,所以事务执行的结果不会保存到RDB快照中。使用RDB快照进行恢复时,数据库中的数据也是一致的。

如果我们使用AOF日志,当事务操作还没有记录在AOF日志中时实例失败,那么使用AOF日志恢复的数据库数据是一致的。如果AOF日志中只记录了部分操作,我们可以使用redis-check-aof来清除事务中已完成的操作,恢复后数据库会保持一致。

一般来说,Redis 中仍然保证数据一致性属性。

隔离

事务隔离要求每个读写事务的对象与其他事务的操作对象是分开的,即事务在提交之前对其他事务是不可见的。

这里对Redis中事务的隔离性进行分析,Redis中事务的隔离性将从以下两个方面进行分析

1、如果在命令排队执行EXEC之前有并发操作

由于Redis只是在事务提交之前将命令放入队列,如果在命令入队和执行EXEC之前有并发操作,这种情况下,事务不是孤立的。

这种情况下,可以用watch来实现,我们举个栗子,看看watch怎么用

1、客户端1首先用watch监听一个key,然后启动一个事务,在事务中写入一些命令;

127.0.0.1:6379> set test-mult-key 100
OK
127.0.0.1:6379> watch test-mult-key
OK
127.0.0.1:6379> MULTI
OK

127.0.0.1:6379> DECR test-mult-key
QUEUED
127.0.0.1:6379> DECR test-mult-key
QUEUED

2、客户端2在客户端1事务提交之前修改密钥;

127.0.0.1:6379> DECR test-mult-key
(integer) 99

3、客户端1提交事务;

127.0.0.1:6379> EXEC
(nil)

从上面的结果我们可以看出,如果在使用watch之后在事务之外修改了当前key值,那么当前事务就会放弃这个事务的执行。这样就实现了事务隔离。

1、如果事务提交后还有并发操作

在这种情况下没有问题。 Redis 会先执行事务中的命令,然后再执行后面的命令,因为 Redis 是单线程执行命令的。在这种情况下,可以保证交易。隔离。

坚持

Redis 会丢失数据。如果数据库在数据被持久化之前就宕机了,一些数据将无法及时持久化而丢失。

因此,Redis 无法保证事务的持久性。

为什么 Redis 不支持回滚

为什么 Redis 没有事务回滚?有以下两个考虑

1、支持回滚会对 Redis 的简单性和性能产生很大影响;

2、Redis 只有语法错误或键值类型操作错误。这些问题应该在开发中解决,不应该出现在生产中。

基于以上两点,目前Redis不支持事务回滚。

源码分析

这里简单分析一下Redis中事务的实现过程

© 版权声明
THE END
喜欢就支持一下吧
点赞112赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容