多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
传统的关系型数据库中,一个事务一般都具有`ACID`特性。那么现在就让我们来分析一下`Redis`是否也满足这`ACID`四大特性。 #### A - 原子性 在讨论事务的原子性之前,我们先来看`2`个例子。 * 模拟事务在执行命令前发生异常。依次执行以下命令: ~~~java multi //开启事务 set name lonely_wolf //设置 name,此时 Redis 会将命令放入队列 get //执行一个不完成的命令,此时会报错 exec //在发生异常后提交事务 ~~~ 最终得到了如下图所示的结果,我们可以看到,当命令入队时报错,事务已经被取消了: ![](https://img.kancloud.cn/76/fa/76fa5b783496dff0e11ad543ae9b1017_839x165.png) * 模拟事务在执行命令前发生异常。依次执行以下命令: ~~~java flushall //为了防止影响,先清空数据库 multi //开启事务 set name lonely_wolf //设置 name,此时 Redis 会将命令放入队列 incr name //这个命令只能用于 value 为整数的字符串对象,此时执行会报错 exec //提交事务,此时在执行第一条命令成功,执行第二条命令失败 get name //获取 name 的值 ~~~ 最终得到了如下图所示的结果。我们可以看到,当执行事务报错的时候,之前已经成功的命令并没有被回滚,也就是说**在执行事务的时候某一个命令失败了,并不会影响其它命令的执行,即`Redis`的事务并不会回滚**: ![](https://img.kancloud.cn/e3/ea/e3eae5d78bc16e6faa81cf7b1114a74f_832x262.png) #### Redis 中的事务为什么不会滚 这个问题的答案在`Redis`官网中给出了明确的解释: ![](https://img.kancloud.cn/eb/3b/eb3b0cdb575364caf02ee483ddac543d_889x404.png) 总结起来主要就是`3`个原因: * `Redis`作者认为发生事务回滚的原因大部分都是程序错误导致,这种情况一般发生在开发和测试阶段,而生产环境很少出现。 * 对于逻辑性错误,比如本来应该把一个数加`1`,但是程序逻辑写成了加`2`,那么这种错误也是无法通过事务回滚来进行解决的。 * `Redis`追求的是简单高效,而传统事务的实现相对比较复杂,这和`Redis`的设计思想相违背。 #### C - 一致性 一致性指的就是事务执行前后的数据符合数据库的定义和要求。这一点`Redis`中的事务是符合要求的,上面讲述原子性的时候已经提到,不论是发生语法错误还是运行时错误,错误的命令均不会被执行。 #### I - 隔离性 事务中的所有命令都会按顺序执行,在执行`Redis`事务的过程中,另一个客户端发出的请求不可能被服务,这保证了命令是作为单独的独立操作执行的。所以`Redis`当中的事务是符合隔离性要求的。 #### D - 持久性 如果`Redis`当中没有被开启持久化,那么就是纯内存运行的,一旦重启,所有数据都会丢失,此时可以认为`Redis`不具备事务的持久性;而如果`Redis`开启了持久化,那么可以认为`Redis`在特定条件下是具备持久性的。