Redis 中的事务分析,Redis 中的事务可以满足ACID属性吗?

Redis 中的事务

什么是事务

数据库事务( transaction )是访问并可能操作各种数据项的一个数据库操作序列,这些操作 要么全部执行,要么全部不执行,是一个不可分割的工作单位 。事务由事务开始与事务结束之间执行的全部数据库操作组成。

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

1、原子性(Atomicity)

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

  • 整个数据库事务是不可分割的工作单位;

  • 只有使数据库中所有的数据库操作都执行成功,才算整个事务成功;

  • 事务中任何一个 SQL 执行失败,已经执行成功的 SQL 也必须撤回,数据库应该退回到执行事务之前的状态;

2、一致性(Consistency)

事务的执行使数据从一个状态转换为另一个状态,在事务开始之前和事务结束之后,数据库的完整性约束没有被破坏。

有点绕,这里举个栗子

如果一个名字字段,在数据库中是唯一属性,执行了事务之后,涉及到了对该字段的修改,事务执行过程中发生了回滚,之后该字段变的不唯一了,这种情况下就是破坏了事务的一致性要求。

因为上面事务执行的过程中,导致里面名字字段属性的前后不一致,即数据库的状态从一种状态变成了一种不一致的状态。

上面的这个栗子就是数据库没有遵循一致性的表现。

3、隔离性(Isolation)

事务的隔离性要求每个读写事务的对象对其他事务的操作对象相互分离,即该事务提交前对其他事务都不可见。

通常使用锁来实现,数据库系统中会提供一种粒度锁的策略,允许事务仅锁住一个实体对象的子集,以此来提高事务之间的并发度。

4、持久性(Durability)

对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障。

当时如果一些人为的或者自然灾害导致数据库机房被破坏,比如火灾,机房爆炸等。这种情况下提交的数据可能会丢失。

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

分析下 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 命令时候,命令的类型不匹配。

栗如:我们对一个 value 为 string 类型的 key,执行 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
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 中事务原子性的总结&

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值