Redis事务
参考资料:
https://www.cnblogs.com/wkfvawl/p/15754956.html
事务
1.1 事务定义
Redis 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
事务可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其他命令插入,不许加塞。
redis是单线程为什么还要事务?
redis 利用单线程 IO多路复用 实现了 单命令操作的原子性,但是多个命令的操作就不具备原子性
1.2 事务相关指令
- 从输入 multi 命令开始,输入的命令都会依次进入命令队列中,但不会执行,至到输入 exec 后,Redis 会将之前的命令队列中的命令依次执行。
- 组队的过程中可以通过 discard 来放弃组队。
- 组队中某个命令出现了报告错误,执行时整个的所有队列会都会被取消。
- 如果执行阶段某个命令报出了错误(类比运行时异常),则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。
1.3事务特性
-
单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
-
没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在“事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题。
-
不保证原子性:Redis 同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。
假设有这么一个场景:有 3 个人有你的账户,同时去参加双十一抢购
悲观锁&乐观锁
悲观锁(Pessimistic Lock),每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁。这样别人想拿这个数据就会 block 直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁(Optimistic Lock),每次去拿数据的时候都认为别人不会修改,所以不会上锁。但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis 就是利用这种 check-and-set 机制实现事务的。
watch|unwatch
- watch
在执行multi
之前,先执行watch key1 [key2 ...]
,可以监视一个(或多个) key,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
- unwatch
取消watch
命令对所有 key 的监视。如果在执行 watch 命令之后,exec 命令或 discard 命令先被执行了的话,那么就不需要再执行 unwatch 了。
pipeline和事务的区别
-
pipeline是客户端的行为,对于服务器来说是透明的:pipeline是将要发送的命令都存储在客户端,等到需要发送时将所有命令打包一起发送给服务器,pipeline没办法保证原子性
-
事务是服务端行为:客户端向redis服务器发送MULTI指令后,服务器不会再执行该服务器的请求(除特定指令外),而是将客户端的所有请求都装入指令队列中,直到接收到客户端的EXEC指令,这时会将对应该客户端队列中的所有指令都执行并返回结果给客户端。