在传统数据库中,事务是一个不可分割的数据库操作序列,也是数据库并发控制的基本单位,其执行的结果必须使数据库从一种一致性状态到另一种一致性状态。事务是逻辑上的一组操作,要么都执行,要么都不执行。事务具有四大特性(ACID):
(1)原子性(Atomicity): 原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
(2)一致性(Consistency): 事务前后数据的完整性必须保持一致。
(3)持久性(Durability): 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
(4)隔离性(Isolation): 事务的隔离性是指多个用户并发操作数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。 简单来说: 事务之间互不干扰。
Redis 事务是指将多条命令加入队列,一次批量执行多条命令,每条命令会按顺序执行,事务执行过程中不会受客户端传入的命令请求影响。Redis 有以下三个重要的保证:
批量操作在发送 EXEC 命令前被放入队列缓存。
收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。
Redis 事务和关系型数据库的事务不太一样,它不保证原子性,也没有隔离级别的概念。如下:
(1)Redis 事务没有隔离级别的概念: 批量操作在发送 EXEC 命令前被放入队列缓存,并不会被实际执行,也就不存在事务内的查询要看到事务里的更新,事务外查询不能看到。
(2)Redis 不保证原子性: Redis 中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。
Redis 中一个事务从开始到执行会经历以下三个阶段:
第一阶段:开始事务
第二阶段:命令入队列
第三阶段:执行事务
该实例使用 Redis 的事务批量执行多个命令,如下:
127.0.0.1:6379> multi OK 127.0.0.1:6379> set name "hello world" QUEUED 127.0.0.1:6379> set age 20 QUEUED 127.0.0.1:6379> set email "demo@163.com" QUEUED 127.0.0.1:6379> mget name age email QUEUED 127.0.0.1:6379> exec 1) OK 2) OK 3) OK 4) 1) "hello world" 2) "20" 3) "demo@163.com"
上面实例中,使用 multi 命里开启事务,然后开始执行多个 set 和 mget 命令,最后执行 exec 命令提交事务。
下表列出了 Redis 事务的常用命令。
标识一个事务的开启,即开启事务。语法如下:
MULTI
实例:
127.0.0.1:6379> multi OK
执行事务中的所有命令(即提交事务),并将连接状态恢复为正常。注意,使用 WATCH 时,EXEC 仅在未修改被监视的键时才执行命令,从而允许检查和设置机制。语法如下:
EXEC
实例:
127.0.0.1:6379> exec 1) OK 2) OK 3) OK 4) 1) "hello world" 2) "20" 3) "demo@163.com"
刷新事务中所有先前排队的命令,并将连接状态恢复到正常。即放弃事务,这和回滚不一样,Redis 事务不支持回滚。注意,如果使用了 WATCH 命令监听键,DISCARD 命令将取消对连接所监视的所有键的监视。语法如下:
DISCARD
实例:
127.0.0.1:6379> multi OK 127.0.0.1:6379> set name "hxstrive" QUEUED 127.0.0.1:6379> discard OK
监视键的变化,用于实现乐观锁。如果监视的键的值改变了,事务最终会执行失败。语法如下:
WATCH key [key ...]
实例:
(1)使用 watch 命令监听 name 键,如下:
127.0.0.1:6379> watch name OK
(2)使用 multi 和 exec 命令执行事务,如下:
127.0.0.1:6379> multi OK 127.0.0.1:6379> set name "www.hxstrive.com" QUEUED 127.0.0.1:6379> exec (nil) 127.0.0.1:6379> get name "update name"
注意,上面实例执行事务失败了,这是因为在执行事务之前,其他 redis 客户端修改了 name 键的内容为 “update name”。
放弃监视。注意,如果调用了 EXEC 或 DISCARD 命令,则无需手动调用 UNWATCH 命令放弃键的监视。语法如下:
UNWATCH
实例:
127.0.0.1:6379> watch name OK 127.0.0.1:6379> unwatch OK
更多命令请访问 https://redis.io/commands 进行参考。