Redis之Redis的事务

1.Redis的事务是什么

Redis 事务的本质是一组命令的集合,事务支持一次执行多个命令,一个事务中全部命令都会被序列化(redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令).redis

1.1reids事务的特色

1. 事务同命令同样都是Redis最小的执行单位,一个事务中的命令要么都执行,要么都不执行数据库

2.在事务执行过程,会按照顺序串行化执行队列中的命令,其余客户端提交的命令请求不会插入到事务执行命令序列中编程

3.Redis的事务还能保证一个事务内的命令依次执行而不被其余命令插入数组

1.2.Redis的经常使用操做

MULTI, EXEC, DISCARD and WATCH 是Redis事务的基础用来显式开启并控制一个事务,它们容许在一个步骤中执行一组命令。并提供两个重要的保证:bash

1. 事务中的全部命令都会被序列化并按顺序执行。在执行Redis事务的过程当中,不会出现由另外一个客户端发出的请求。这保证 命令队列 做为一个单独的原子操做被执行。服务器

2.队列中的命令要么所有被处理,要么所有被忽略。EXEC命令触发事务中全部命令的执行,所以,当客户端在事务上下文中失去与服务器的链接.ui

1.2.1MULTI 命令

用于标记事务块的开始。Redis会将后续的命令逐个放入队列中,而后才能使用EXEC命令原子化地执行这个命令序列。这个命令的运行格式以下所示:MULTIspa

这个命令的返回值是一个简单的字符串,老是OK。设计

1.2.2. EXEC命令

在一个事务中执行全部先前放入队列的命令,而后恢复正常的链接状态。当使用WATCH命令时,只有当受监控的键没有被修改时,EXEC命令才会执行事务中的命令,这种方式利用了检查再设置(CAS)的机制()。这个命令的运行格式以下所示:EXEC3d

这个命令的返回值是一个数组,其中的每一个元素分别是原子化事务中的每一个命令的返回值。当使用WATCH命令时,若是事务执行停止,那么EXEC命令就会返回一个Null值。(若是在发送EXEC命令前客户端断线了,则Redis会清空事务队列,事务中的全部命令都不会执行。而一旦客户端发送了EXEC命令,全部的命令就都会被执行)

1.2.3. DISCARD命令

清除全部先前在一个事务中放入队列的命令,而后恢复正常的链接状态。若是使用了WATCH命令,那么DISCARD命令就会将当前链接监控的全部键取消监控。这个命令的运行格式以下所示:DISCARD

这个命令的返回值是一个简单的字符串,老是OK。

1.2.4. WATCH命令

当某个事务须要按条件执行时,就要使用这个命令将给定的键设置为受监控的.

1.Watch指令,相似乐观锁,事务提交时,若是Key的值已被别的客户端改变,好比某个list已被别的客户端push/pop过了,整个事务队列都不会被执行

2.经过WATCH命令在事务执行以前监控了多个Keys,假若在WATCH以后有任何Key的值发生了变化,EXEC命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者事务执行失败.这个命令的运行格式以下所示:WATCH key [key ...]

这个命令的返回值是一个简单的字符串,老是OK。对于每一个键来讲,时间复杂度老是O(1)。

1.2.5. UNWATCH命令

清除全部先前为一个事务监控的键。若是你调用了EXEC或DISCARD命令,那么就不须要手动调用UNWATCH命令。这个命令的运行格式以下所示:UNWATCH

这个命令的返回值是一个简单的字符串,老是OK。时间复杂度老是O(1)。

2.Redis 事务的三个阶段

Redis 中的事务从开始到结束也是要经历三个阶段:开启事务,命令入列,执行事务/放弃事务

2.1开启事务阶段

1.multi 命令用于开启事务

2.multi 命令能够让客户端从非事务模式状态,变为事务模式状态,以下图所示

3.注意:multi 命令不能嵌套使用,若是已经开启了事务的状况下,再执行 multi 命令,会提示以下错误:

复制代码
错误:(error) ERR MULTI calls can not be nested
  执行效果,以下代码所示:

127.0.0.1:6379> multi
OK
127.0.0.1:6379> multi
(error) ERR MULTI calls can not be nested复制代码
复制代码

4.当客户端是非事务状态时,使用 multi 命令,客户端会返回结果 OK ,若是客户端已是事务状态,再执行 multi 命令会 报不能嵌套的错误,但不会终止客户端为事务的状态,以下图所示

2.2命令入列阶段

1.客户端进入事务状态以后,将多个命令入队到事务中,接到这些命令并不会当即执行,而是放到等待执行的事务队列里面,命令入列成功后会返回 QUEUED,以下代码所示:

> multi
OK
> set k v
QUEUED
> get k
QUEUED复制代码

2.命令会按照先进先出(FIFO)的顺序出入列,也就是说事务会按照命令的入列顺序,从前日后依次执行。

执行流程以下图所示:

2.3执行事务/放弃事务阶段

执行事务的命令是 exec ,放弃事务的命令是 discard

执行事务示例代码以下:

复制代码
> multi
OK
> set k v2
QUEUED
> exec
1) OK
> get k
"v2"复制代码
复制代码
复制代码

放弃事务示例代码以下:

复制代码
> multi
OK
> set k v3
QUEUED
> discard
OK
> get k
"v2"复制代码
复制代码

3.事务错误&回滚

事务执行中的错误分为如下三类:

1.执行时才会出现的错误(简称:执行时错误)

2.入列时错误,不会终止整个事务;

3.入列时错误,会终止整个事务。

3.1执行时错误

从如下实例结果能够看出,即便事务队列中某个命令在执行期间发生了错误,事务也会继续执行,直到事务队列中全部命令执行完成。

3.2入列时,错误不会致使事务结束

从如下实例结果能够看出,重复执行 multi 会致使入列错误,但不会终止事务,最终查询的结果是事务执行成功了。除了重复执行 multi 命令,还有在事务状态下执行 watch 也是一样的效果

3.3入列错误会致使事务结束

3.4为何不支持事务回滚?

不支持事务回滚的缘由有如下两个:

1.Redis事务的执行时,错误一般都是编程错误形成的,这种错误一般只会出如今开发环境中,而不多会在实际的生产环境中出现,因此他认为没有必要为 Redis 开发事务回滚功能;

2.不支持事务回滚是由于这种复杂的功能和 Redis 追求的简单高效的设计主旨不符合。

4.Redis事务的三个特性

1.单独的隔离操做:事务中的全部命令都会序列化、按顺序地执行。事务在执行的过程当中,不会被其余客户端发送来的命令请求所打断。

2.没有隔离级别的概念:队列中的命令没有提交以前都不会实际的被执行,由于事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个

3.不保证原子性:redis同一个事务中若是有一条命令执行失败,其后的命令仍然会被执行,没有回滚

5.悲观锁与乐观锁

1.悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,因此每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了不少这种锁机制好比行锁,表锁等,读锁,写锁等,都是在作操做以前先上锁

2.乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,因此不会上锁可是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可使用版本号等机制。乐观锁适用于多读的应用类型,这样能够提升吞吐;乐观锁策略:提交版本必须大于记录当前版本才能执行更新

相关文章
相关标签/搜索