工程设计东莞网站建设技术支持,网业无法打开怎么办,购物网站开发总结报告,一份简短的项目计划书背景
在面试中经常会被问到#xff0c;redis支持事务吗#xff1f;事务是怎么实现的#xff1f;事务会回滚吗#xff1f;又是一键三连#xff0c;我下面分析下#xff0c;看看能不能吊打面试官
什么是Redis事务
事务是一个单独的隔离操作#xff1a;事务中的所有命令…背景
在面试中经常会被问到redis支持事务吗事务是怎么实现的事务会回滚吗又是一键三连我下面分析下看看能不能吊打面试官
什么是Redis事务
事务是一个单独的隔离操作事务中的所有命令都会序列化、按顺序地执行。 事务在执行的过程中不会被其他客户端发送来的命令请求所打断。事务是一个原子操作事务中的命令要么全部被执行要么全部都不执行。
总结说redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。
Redis 中的事务如何工作
Redis 事务允许在一个步骤中执行一组命令它们以 MULTI、EXEC、DISCARD 和 WATCH 命令为中心事务中的所有命令都被序列化并按顺序执行。另一个客户端发送的请求永远不会在 Redis 事务执行过程中得到服务。这保证了命令作为单个独立操作执行。
一个事务从开始到执行会经历以下三个阶段
开启事务。命令入队。执行事务或者放弃事务。
其中开启事务使用 multi 命令事务执行使用 exec 命令放弃事务使用 discard 命令。
事务执行流程图可以直观的看下 Redis事务相关命令和使用
MULTI 开启事务redis会将后续的命令逐个放入队列中然后使用EXEC命令来原子化执行这个命令系列。EXEC执行事务中的所有操作命令。DISCARD取消事务放弃执行事务块中的所有命令。WATCH监视一个或多个key,如果事务在执行前这个key(或多个key)被其他命令修改则事务被中断不会执行事务中的任何命令。UNWATCH取消WATCH对所有key的监视。
MULTI 开启事务
multi 命令用于开启事务实现代码如下
# multi 命令可以让客户端从非事务模式状态变为事务模式状态
127.0.0.1:6371 MULTI
OK注意啊multi 命令不能嵌套使用如果已经开启了事务的情况下再执行 multi 命令会提示如下错误
127.0.0.1:6371 MULTI
OK
127.0.0.1:6371(TX) MULTI
(error) ERR MULTI calls can not be nested命令入列
客户端进入事务状态之后执行的所有常规 Redis 操作命令非触发事务执行或放弃和导致入列异常的命令会依次入列命令入列成功后会返回 QUEUED如下代码所示
127.0.0.1:6371 MULTI
OK
127.0.0.1:6371(TX) set k 1
QUEUED
127.0.0.1:6371(TX) set b 1
QUEUED用户可以发出多个命令命令会按照先进先出FIFO的顺序出入列Redis 不会执行这些命令而是将它们排队。需要调用 EXEC执行事务 所有命令才会执行。
执行事务/放弃事务
执行事务的命令是 exec放弃事务的命令是 discard。
执行事务:
127.0.0.1:6371 MULTI
OK
127.0.0.1:6371(TX) set k 1
QUEUED
127.0.0.1:6371(TX) set b 1
QUEUED
127.0.0.1:6371(TX) EXEC
1) OK
2) OKEXEC 返回一个回复数组其中每个元素都是事务中单个命令的回复与发出命令的顺序相同。
放弃事务
127.0.0.1:6371 MULTI
OK
127.0.0.1:6371(TX) set k 2
QUEUED
127.0.0.1:6371(TX) set b 2
QUEUED
127.0.0.1:6371(TX) DISCARD
OK
127.0.0.1:6371 get k
1
127.0.0.1:6371 get b
1MULTI开启事务后命令入队取消事务队列里面的命令是不会执行的。 设置 k、b两个key的值为2取消事务后值还是保留以前是 1说明取消事务后队列里面的命令没有执行
事务出现错误的处理
事务执行中的错误分为以下两类
入列的命令语法错误终止事务入列命令运行时错误不会终止事务
入列的命令语法错误终止事务
分别设置 k1、k2的值为1然后开启事务设置值k1、k2的值为2其中 设置k2的时候 命令出错 sets执行事务入列的命令未执行终止了事务
127.0.0.1:6371 set k1 1
OK
127.0.0.1:6371 set k2 1
OK
127.0.0.1:6371 get k1
1
127.0.0.1:6371 get k2
1
127.0.0.1:6371 MULTI
OK
127.0.0.1:6371(TX) set k1 2
QUEUED
127.0.0.1:6371(TX) sets k2 2
(error) ERR unknown command sets, with args beginning with: k2 2
127.0.0.1:6371(TX) EXEC
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6371 get k1
1
127.0.0.1:6371 get k2
1入列的命令运行时错误不会终止事务
在开启事务后修改k1值为2但将k2的类型作为List进行元素操作在运行时检测类型错误最终导致事务提交失败此时事务并没有回滚而是跳过错误命令继续执行 结果k1值改变
127.0.0.1:6371 get k1
1
127.0.0.1:6371 get k2
1
127.0.0.1:6371 MULTI
OK
127.0.0.1:6371(TX) set k1 2
QUEUED
127.0.0.1:6371(TX) LPOP k2
QUEUED
127.0.0.1:6371(TX) exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6371 get k1
2运行时发生错误事务未终止事务不会回滚呢
为什么事务不会回滚
Redis 官方文档的解释如下 Redis 命令只会因为错误的语法而失败并且这些问题不能在入队时发现或是命令用在了错误类型的键上面这也就是说从实用性的角度来说失败的命令是由编程错误造成的而这些错误应该在开发的过程中被发现而不应该出现在生产环境中。
watch 监控
WATCH 用于为 Redis 事务提供检查和设置 (CAS) 行为。
watch 命令用于客户端并发情况下为事务提供一个乐观锁CASCheck And Set也就是可以用 watch 命令来监控一个或多个变量如果在事务的过程中某个监控项被修改了那么整个事务就会终止执行,并且 EXEC 返回 Null 回复以通知事务失败
watch 基本语法如下
watch key [key ...]举个例子看下修改监控的key以后事务是否会终止
客户端1设置k1的值为1k2的值1然后 watch 监控k1开启事务设置k1为2k2为2客户端2修改k1的值为23客户端1执行事务
客户端1执行命令如下
127.0.0.1:6371 set k1 1
OK
127.0.0.1:6371 set k2 1
OK
127.0.0.1:6371 WATCH k1
OK
127.0.0.1:6371 MULTI
OK
127.0.0.1:6371(TX) set k1 2
QUEUED
127.0.0.1:6371(TX) set k2 2
QUEUED
127.0.0.1:6371(TX) EXEC
(nil)
127.0.0.1:6371 get k1
3
127.0.0.1:6371 get k2
1客户端2执行命令如下
127.0.0.1:6371 set k1 3
OK从上面的结果可以看出监控了k1客户端2修改了k1的值事务是中止的
如果不再监控key使用UNWATCH 取消监控
代码实现
使用jedis客户端实现代码如下
public static void main(String[] args) {Jedis jedis new Jedis(10.1.250.157, 6379);jedis.auth(google00);jedis.set(k,1);//监控keyjedis.watch(k);//开启事务Transaction tx jedis.multi();// 命令入队tx.set(k,2);tx.set(k1,3);//执行事务tx.exec();//取消监控jedis.unwatch();}总结
redis是支持事务的开启事务后命令入队命令的语法如果有错执行事务会中止如果执行命令的时候发现命令有问题其他命令能正常执行事务是不会回滚的因为redis的回滚会对redis的简单性和性能造成严重影响。
特别注意 事务中的命令要么全部被执行要么全部都不执行 。是执行不是成功哦更我们平时用的关系型数据库是有差别的。