Redis事务
一、概念
1、Redis 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行 2、事务在执行的过程中,不会被其他客户端发送来的命令请求所打断 3、Redis 事务的主要作用就是串联多个命令防止别的命令插队
二、Redis事务三特性
1.单独的隔离操作
- 事务中的所有命令都会序列化、按顺序地执行
- 事务在执行的过程中,不会被其他客户端发送来的命令请求所打断
2.没有隔离级别的概念
队列中的命令(指令), 在没有提交前都不会实际被执行
3.不保证原子性
事务执行过程中, 如果有指令执行失败,其它的指令仍然会被执行, 没有回滚
三、相关指令
- 从输入 Multi 命令开始,输入的命令都会依次进入命令队列(
QUEUED
)中,但不会执行(类似 Mysql 的start transaction
开启事务) - 输入 Exec 后,Redis 会将之前的命令队列中的命令依次执行(类似 Mysql 的
commit
提交事务) - 组队
Multi
的过程中可以通过discard
来放弃组队(类似 Mysql 的rollback
回顾事务) - 如果在组队阶段报错, 会导致 exec 失败, 那么事务的所有指令都不会被执行,这个情况是具有原子性的
四、事务冲突及解决方案
例如:在购票时,如果只有10张票,当同时有三个请求购票,第一个请求购票6张,第二个请求购票5张,第三个请求购票1张,如果没有事务控制就会出现超卖现象。
1.悲观锁
Pessimistic Lock--总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。
Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。传统的关系型数据库里边也用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
缺点:性能较低
2.乐观锁
Optimistic Lock--总是乐观地假设最好的情况,每次去拿数据的时候都认为别人不会修改这个数据,所以不会上锁,只会要对数据进行更新时判断一下在此期间(拿到数据到更新的期间)别人有没有去更改这个数据,可以使用版本号机制和CAS算法实现。
乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis 就是利用这种
check-and-set
机制实现事务的
3.watch & unwatch
如上图所示,初始值 k1=110 k2=30
在开启事务之前两个Redis连接都执行了 watch k1
指令,相当于对k1的版本号进行了一个监控
第一个连接先执行事务 exec
,执行成功
第二个连接由于k1的值已被改变,事务终止,就返回了nil,队列中的k1和k2都没有改变
unwatch
:取消 watch 命令对所有 key 的监视
如果在执行 watch
命令后,exec 命令或 discard 命令先被执行了的话,那么就不需要再执行 unwatch
了