目录
前言
Redis中的事务和MySQL中事务概念上类似的,都是把一组操作打包成一个整体,然后在批量执行这个整体中内容.
Redis事务和MySQL中事务的区别
- Redis没有回滚机制,既是事务中有部分命令执行失败,已经执行完成的命令不会撤销,Redis中的事务只能做到批量执行,不能做到一个失败就恢复到初始状态.
- 不保证一致性,Redis事务中不涉及约束,也没有回滚
- 不需要隔离性, 因为Redis本身就是单线程执行处理命令的,不会涉及到并发执行事务
- 不需要持久性, 因为Redis是基于内存的数据库,是否开启持久化是Redis-server的事情,和事务无关.
Redis事务本质是在server端创建了一个事务队列,每次客户端执行的命令,都会先把这个命令加入到事务队列中,但是不会立即执行命令.而是等到EXEC执行事务的命令之后,才开始批量的执行事务队列中的命令.
注意: Redis的事务相比MySQL来说,是弱化很多的,只能保证事务中的一组操作是连续的,不会被其他客户端加塞而已.
事务操作
MULTI
开启一个事务,开启成功后返回ok
local:0>multi
"OK"
local:0>
当我们成功开启了一个事务之后,就可以给这个事务队列中添加命令了.
local:0>set hello 1
"QUEUED"
local:0>set hello2 2
"QUEUED"
local:0>set hello3 3
"QUEUED"
local:0>
每次添加一个操作,都会给我们返回一个QUEUED,说明命令已经加入事务队列中了.
EXEC
执行事务,开始批量的执行事务队列中的所有命令.这时客户端才真正的命令发送给服务器
local:0>exec
1) "OK"
2) "OK"
3) "OK"
这时就可以获取在事务中执行的值了
local:0>get hello
"1"
local:0>get hello2
"2"
local:0>get hello3
"3"
local:0>
DISCARD
直接放弃当前事务,清空事务队列中的所有命令,这些命令不会被执行到
local:0>multi
"OK"
local:0>set k 1
"QUEUED"
local:0>set k2 2
"QUEUED"
local:0>discard
"OK"
local:0>get k
null
local:0>get k2
null
local:0>
WATCH
在执行事务的时候,如果事务中的某个值被其他客户端修改了,此时就会出现数据不一致的问题.
客户端1先执行
local:0>multi
"OK"
local:0>set key1 100
"QUEUED"
local:0>
客户端2再执行
local:0>set key1 200
"ok"
local:0>
客户端1最后执行
local:0>exec
1) "OK"
此时的key1的值是多少 ?
从整体执行的时间节点来看,
是客户端1 先执行的 set key 100.
客户端2 后执行的 set key 200.
但是从实际的执行时间看, 是客户端2先执行的, 客户端1后执行的.
local:0>get key1
"100"
local:0>
结果是100.
可以看出这里的操作是有分险的. 即使不保证数据一致性,那也要告诉用户当前的操作有分险.
watch命令就是用来解决这个问题的.
watch在客户端上监控一组具体的key.
当事务开启的时候,如果对watch监控的key进行修改,就会记录当前key的版本号,(这个版本号就是一个简单的整数,每次修改监控的key之后,版本号就会增加,服务器使用版本号来维护每个key的版本号情况).
在真正提交事务的时候, 如果发现当前服务器上的 key 的版本号已经超过了事务开始时的版本号, 就 会让事务执行失败. (事务中的所有操作都不执行)
客户端1先执行
local:0>watch key2
"OK"
local:0>multi
"OK"
local:0>set key2 200 # 进行修改, 从服务器获取 key2的版本号是 0. 记录 key2的版本号. (还没真修改呢, 版本号不变)
"QUEUED"
local:0>
只是加入队列,没有提交事务执行
客户端2再执行
local:0>set key2 300 # 修改成功, 使服务器端的 key2 的版本号 0 -> 1
"OK"
local:0>
最后客户端1执行
local:0>exec
local:0>get key2
"300"
local:0>
说明这次事务已经取消执行了,事务里面的命令也没有执行.最后的结果是客户端2执行的结果.