目录
redis事务
1、redis事务命令
2、示例
redis管道
1、管道命令
2、示例
redis事务
在Redis中,事务是一组命令的有序队列,可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入。
redis事务与数据库事务对比
单独的隔离操作 | Redis的事务仅仅是保证事务里的操作会被连续独占的执行,redis命令执行是单线程架构,在执行完事务内所有指令前是不可能再去同时执行其他客户端的请求的 |
没有隔离级别的概念 | 因为事务提交前任何指令都不会被实际执行,也就不存在"事务内的查询要看到事务里的更新,在事务外查询不能看到"这种问题了 |
不保证原子性 | Redis的事务不保证原子性,也就是不保证所有指令同时成功或同时失败,只有决定是否开始执行全部指令的能力,没有执行到一半进行回滚的能力 |
排它性 | Redis会保证一个事务内的命令依次执行,而不会被其它命令插入 |
1、redis事务命令
DISCARD | 取消事务,放弃执行事务块内的所有命令。 |
EXEC | 执行所有事务块内的命令。 |
MULTI | 标记、个事务块的开始。 |
UNWATCH | 取消WATCH命令对所有key的监视。 |
WATCH key [key ...] | 监视一个(或多个)key,如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断。 |
2、示例
正常执行:
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set k1 1
QUEUED
127.0.0.1:6379(TX)> set k2 2
QUEUED
127.0.0.1:6379(TX)> set k3 3
QUEUED
127.0.0.1:6379(TX)> INCR count
QUEUED
127.0.0.1:6379(TX)> EXEC
1) OK
2) OK
3) OK
4) (integer) 1
127.0.0.1:6379> get k1
"1"
放弃事务:multi discard
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> incr count
QUEUED
127.0.0.1:6379(TX)> discard
OK
127.0.0.1:6379> get k1
"1"
全体连坐,错一个所有的命令都不执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1
"1"
冤头债主,错误的命令不执行,正确的执行
127.0.0.1:6379> del meail
(integer) 1
127.0.0.1:6379> set emial 1@qq.com
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> incr emial
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (error) ERR value is not an integer or out of range
127.0.0.1:6379> get k1
"v1"
所以事务执行时报错不会像数据库要么成功要么都不执行
watch监控:Redis使用watch来提供乐观锁定,类似于CAS(Check-and-Set)watch命令是一种乐观锁的实现,Redis在修改的时候会检测数据是否被更改,如果更改了,则执行失败
正常情况
127.0.0.1:6379> set balance 100
OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get balance
"100"
127.0.0.1:6379> watch balance
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 a1
QUEUED
127.0.0.1:6379(TX)> set balance 110
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> get balance
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
3) "a1"
4) "110"
异常情况,在监控下修改
unwatch放弃监控
注意:一旦执行了exec之前加的监控锁都会被取消掉了,当客户端连接丢失的时候(比如退出链
接),所有东西都会被取消监视。
redis管道
问题:如果同时需要执行大量的命令,那么就要等待上一条命令应答后再执行,这中间不仅仅多了RTT(Round Time Trip),而且还频繁调用系统IO,发送网络请求,同时需要redis调用多次read()和write()系统方法,系统方法会将数据从用户态转移到内核态,这样就会对进程上下文有比较大的影响。
管道(pipeline)可以一次性发送多条命令给服务端,服务端依次处理完完毕后,通过一条响应一次性将结果返回,通过减少客户端与redis的通信次数来实现降低往返延时时间。pipeline实现的原理是队列,先进先出特性就保证数据的顺序性。
1、管道命令
#docker操作
cat cmd.txt | docker exec -i redis2 redis-cli -a 123456 --pipe
#linux系统操作
cat cmd.txt | redis-cli -a 123456 --pipe
2、示例
将你要执行的命令写入一个文件里
管道pipeline与原生命令对比
原生批量命令是原子性(例如:mset,mget),pipeline是非原子性。
原生批量命令一次只能执行一种命令,pipeline支持批量执行不同命令。
原生批命令是服条端实现,而pipeline需要服务端与客户端共同完成。
管道pipeline与事务对比
事务具有原子性,管道不具有原子性。
管道一次性将多条命令发送到服务器,事务是一条一条的发,事务只有在接收到exec命令后才会执行,管道不会。
执行事务时会阻塞其他命令的执行,而执行管道中的命冬时不会
使用管道pipeline注意事项
pipeline缓冲的指令只是会依次执行,不保证原子性,如果执行中指令发生异常,将会继续执行后续的指令。
使用pipeline组装的命令个数不能太多,不然数据量过大客户端阻塞的时间可能过久,同时服务端此时也被迫回复一个队列答复,占用很多内存。