一、事务
Redis 的事务功能允许用户将多个命令包裹起来,然后一次性地、按顺序地执行被包裹的所有命令。在事务执行的过程中,服务器不会中断事务而改去执行其他命令请求,只有在事务包裹的所有命令都
被执行完毕之后,服务器才会去处理其他命令请求。
事务示例:
现在, 让我们假设 SETEX 命令并不存在于 Redis , 并且 SET 命令也不支持 EX seconds 参数, 如果我们要自己来实现一个 SETEX 命令的话, 那么我们可能会使用以下代码:
def SETEX(key, seconds, value):
SET key value
EXPIRE key seconds
在一般情况下,这个自制的 SETEX 命令可以达到设置键值对并设置生产时间的效果,但是这个自制的SETEX 存在一个缺陷:如果服务器在成功地执行 SET 命令并保存数据之后崩溃,那么 EXPIRE 命令将没办法执行。
这时虽然我们已经设置了键, 但并没有为键设置过期时间, 如果我们没有发觉的话, 那么这个本来应该定期被删除的键就会一直留在数据库里面占用着内存, 甚至造成之后的程序出错。
二、事务命令
为了避免遇上以上所说的情况, 我们需要用到 Redis 的事务功能, 通过事务, 我们可以让 Redis一次性地执行多个命令, 并且确保事务中的命令要么就全部都执行,要么就一个都不执行。
MULTI : 开始一个新的事务
DISCARD : 放弃事务
EXEC : 执行事务中所有命令
以下分别对事务命令进行描述:
MULTI
开始一个事务。
在这个命令执行之后,客户端发送的所有针对数据库或者数据库键的命令都不会被立即执行,而是被放入到一个事务队列里面,并返回 QUEUED 表示命令已入队。
redis> MULTI # 开始一个事务 OK redis> SET msg "hello world" # 将这个 SET 命令放入事务队列 QUEUED redis> EXPIRE msg 10086 # 将这个 SET 命令放入事务队列 QUEUED
DISCARD
取消事务,放弃执行事务队列中的所有命令。
redis> MULTI OK redis> SET msg "hello world" QUEUED redis> EXPIRE msg 10086 QUEUED redis> DISCARD # 事务已被取消 OK redis> SET msg "hello world" OK
EXEC
执行事务,按照命令被入队到事务队列中的顺序,执行事务队列中的所有命令。命令的返回值是一个列表,列表里包含了事务队列中所有被执行命令的返回值。
redis> MULTI OK redis> SET msg "hello world" QUEUED redis> EXPIRE msg 10086 QUEUED redis> EXEC 1) OK # SET 命令的返回值 2) (integer) 1 # EXPIRE 命令的返回值
使用事务保证操作的安全性
之前的自制 SETEX 的定义,带有安全缺陷:
def SETEX(key, seconds, value):
SET key value
EXPIRE key seconds # 如果服务器在 SET 命令执行之后崩溃,那么 EXPIRE 将无法执行
使用事务实现的自制 SETEX 的定义,没有安全缺陷,服务器保证要么两个命令都执行,要么就两个命令都不执行:
def SETEX(key, seconds, value):
MULTI
SET key value
EXPIRE key seconds
EXEC
三、流水线和事务的区别
流水线:确保多条命令会被一起发送;
事 务 :确保多条命令会被一起执行;
(PIPELINE_START) SET msg “hello world” # 这两条命令会被一起发送至服务器 EXPIRE msg 10086 (PIPELINE_END)
MULTI SET msg “hello world” # 这两条命令会一起被服务器执行 EXPIRE msg 10086 EXEC