Redis事务(Redis事务与普通关系型数据库事务的区别)

前言

Redis作为非关系型数据库中的一种,因为其基于内存、单线程、支持持久化、拥有着高速的读写速度而又支持多种数据类型、支持原生集群等特点而被广泛使用。这篇博文主要讨论下Redis事务与关系型数据库(比如MySQL)事务之间的区别。

Redis事务

Redis事务与MySQL事务一样,一次事务可以执行多条命令,在事务执行时命令按顺序执行。由MULTI命令标志着事务的开始,EXEC命令标志着开始执行事务内的所有命令。MULTI和EXEC命令将一个事务的过程划分为两个阶段,MULTI命令开启组队阶段,在组队阶段主要是将命令依次送入缓冲队列中;EXEC命令开启执行阶段,从缓冲队列中取出命令执行。

在组队阶段,其它客户端的命令会影响该事务内命令所操作的key,可以通过WATCH命令来监听一个或者多个key来判断key值是否改变,一旦有一个key值改变则中断事务放弃事务中的所有命令,再者,在组队阶段若发生错误,Redis会中断事务放弃事务中的所有命令。
在这里插入图片描述
一旦执行EXEC命令,事务进入执行阶段,则外界其它客户端的命令无法插入其中,无法影响事务操作的结果。其它客户端无法插入到事务的众多命令中,则无法影响事务操作结果的原因在于Redis服务端处理请求是单线程,在处理这个事务的一段时间内,服务端无法并行的执行其它命令,自然也就无法影响事务操作结果(即使使用Redis集群,Redis会根据事务命令操作的key值将命令请求分配到对应的服务器上,Redis服务端在不同的机器上也是单线程处理请求,在那一段时间内只能执行事务的命令)。再者事务在执行过程中若有命令执行失败,则该命令不被执行而是跳过该命令,其它命令继续执行,也就是说Redis事务在执行过程中不因某一个命令的失败而产生事务回滚操作。例如一个事务包含A、B、C、D四条命令,执行过程中依次执行,执行完A、B,在执行C时发生错误,则跳过命令C,继续执行D命令,事务结束后A、B、D命令成功执行,产生影响结果。
在这里插入图片描述

Redis命令

MULTI开启组队阶段。
EXEC开启执行阶段。
DISCARD命令只能在组队阶段使用。
WATCH和UNWATCH命令也是在组队阶段使用,用以实现对key的监听,防止key被其它命令所改动。这种机制其实就相当于乐观锁,由于数据存储在内存中,无需进行耗时的I/O,其实事务很快就能执行完成,则Redis乐观的认为我无需加锁,然后通过WATCH命令来进行检测,若是数据不幸被改动了,我再来补偿,将被改动的消息抛给用户程序进行处理。
在这里插入图片描述

事务的应用场景

Redis命令根据其特点应用于一组命令需要同一批执行,且要保证一组命令在执行的过程之中不被其它命令插入。例如商品秒杀。

Redis事务与普通关系型数据库事务的区别

一般提到事务,我们都能想到事务的四特性(ACID),这里将从事务特性的角度来分析Redis事务与普通关系型数据库事务的区别。

事务特性(ACID)

原子性(Atomicity): 事务的原子性是指事物是最小的执行单位,不允许分割,事务内的一系列操作,要不都执行,要不都不执行。

一致性(Consistency): 事物的提交只会导致数据库的状态从一个一致性状态到另外一个一致性状态,换句话来说就是事务一系列操作的中间操作导致的中间不一致状态不会让别的事务看到。一致性状态指的是多个事务访问到的数据库的数据和数据结构是一致的。

隔离性(Isolation): 事务的隔离性是指并发事务在执行过程中不能相互影响,其对数据库的影响和它们串行执行时一样。

持久性(Durability): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不会导致提交改变结果的丢失。

事务特性区别分析

原子性分析: 首先来看下Redis是否具有原子性,首先Redis不支持事务回滚操作,Redis事务在组队阶段若某一个命令出错会中断事务放弃事务内的所有命令;但到了真正的执行阶段,若事务内某一个命令执行出错,却不影响其它命令,抛弃出错命令,其它命令照常执行,以此看来Redis并不满足原子性的事务内命令要不都执行要不都不执行的特性,因此Redis事务并没有原子性。从这个角度来看,Redis事务更像一个批量处理的操作。

隔离性分析: Redis是用单线程来处理请求,天然就具有隔离性,因为它本来就是串行的执行命令,具有最高的隔离级别。其它客户端的命令无法在Redis事务执行的过程中插入进去,自然也无法影响其事务执行。

持久性分析: Redis与Memcached的一个区别就是Redis支持持久化,Redis支持RDB(快照)和AOF两种持久化机制(当然Redis也可以设置为不进行持久化)。RDB的机制是每隔一段时间将内存中发生变化的数据以快照的方式存储到磁盘dump.rdb文件中;而AOF是每当有写命令执行时,都将写命令写入磁盘的appendonly.aof文件中(也可以设置为每隔一秒将写命令写入文件),以便机器重启时通过写命令再将数据更新到内存中,AOF方式持久化的实时性更好。以此看来Redis事务其实是具有持久性的,若它使用的是AOF方式的每当有写命令,都将命令写入磁盘文件,可以保证事务的持久性。

一致性分析: Redis单线程处理请求以及Redis事务在执行时不允许别的命令插入的特点就决定了事务中间操作导致的中间一致性状态不会被其它事务所看到,且Redis可在机器宕机后通过持久化的文件恢复到一致性状态,从这些角度看,Redis事务貌似具有一致性。但Redis不支持事务回滚,意味着它很可能导致现实意义中的不一致性,例如常见的例子银行转账,账号A给B转账100,命令有两条,分别是账号A减去100和账号B加上100,若第一条命令出错,而第二条命令正常执行,就导致了不一致性。其实Redis为了保持简洁和效率,放弃了事务回滚,也就放弃了原子性和一致性,因为事务回滚主要是在命令出错时保持数据的一致性,而在Redis中,命令出错主要是编程人员使用错误,而这点应该在开发中被发现,而不是在使用过程中,因此Redis认为我不需要为你的错误买单,Redis放弃了事务回滚的机制。因此Redis不具有传统事务的一致性。

Redis常用来做缓存而不是真正意义上的数据库,不是用来永久存储数据,因此Redis的很多设计理念与普通关系型数据库并不一致,Redis事务为了简洁和快速抛弃了事务回滚,也就同时抛弃了原子性和一致性,事务操作更像是一个批量操作了,只是在批量操作过程中不允许别的事务或者命令加塞,插入进来。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章