码迷,mamicode.com
首页 > 其他好文 > 详细

Redis事务

时间:2019-03-19 10:24:13      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:atom   服务   原理   字符串类   简单   就是   redis事务   redis命令   问题   

  Redis事务以MULTI开始,中间添加多种命令,这些命令不会立即执行,而是被放入到一个队列中,当执行EXEC时,队列中的所有命令被依次执行。

  当命令放在MULTI中,但还未执行EXEC时,每个命令返回值为QUEUED,Redis事务将多个命令使用MULTI包括起来,调用EXEC一起执行,减少与客户端之间通信往返次数,提升执行多个命令时的性能

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set key 1
QUEUED
127.0.0.1:6379> LPUSH list a
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (integer) 1
127.0.0.1:6379> keys *
1) "list"
2) "key"
127.0.0.1:6379> 

  从2.6.5版本开始,在执行EXEC之前,redis命令在加入队列时,如果出现错误(一般为语法错误),则执行EXEC时,该事务不会被执行,并自动丢弃

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET flag 1
QUEUED
127.0.0.1:6379> LPUSH list a
QUEUED
127.0.0.1:6379> LPUSH list
(error) ERR wrong number of arguments for lpush command
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> keys *
(empty list or set)  ## 正确的脚本也未执行,当前事务被丢弃
127.0.0.1:6379> 

  在2.6.5版本之前,执行MULTI之后,EXEC之前发生错误时,当执行EXEC命令,redis忽略掉错误命令,执行正确的命令。

  在EXEC执行之后发生错误,其他正确的命令会被执行,redis不会回滚

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set mykey 1
QUEUED
127.0.0.1:6379> LPUSH mykey 12
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> keys *
1) "mykey"      ## 正确命令被执行,错误的命令被丢弃
127.0.0.1:6379> 

  Redis不支持事务回滚,官网给出了两点理由

1、redis命令只有两个错误会出现,一个为错误的语法结构,一个为对数据类型使用错误的方法处理,如上例中使用LPUSH操作字符串类型的mykey。这两个问题在开发环境自测的时候就能够发现。

2、redis内部的结构简单,而且速度更快,因为它不需要回滚功能。

  DISCARD命令可用于终止当前事务并丢弃,也即是清空队列中的命令。该命令必须应用在MULTI命令中

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set key v
QUEUED
127.0.0.1:6379> set mykey 2
QUEUED
127.0.0.1:6379> LPUSH list aa
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> EXEC
(error) ERR EXEC without MULTI     ## 已经不再事务范围之内,也即是当前事务已经在执行DISCARD的时候结束
127.0.0.1:6379>

  以上为redis简单的事务操作,但以上存在数据安全问题

  假设小王暑假打工赚了一百块钱,存了起来,但由于小王所在地的一些方面的原因,钱放进去,但还未执行EXEC

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET money 100
QUEUED
127.0.0.1:6379> 

  此时小王妈妈去银行给小王汇过来1000元,并且营业员服务周到,各种硬件完备,很快就办完了业务

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set money 1000
QUEUED
127.0.0.1:6379> EXEC
1) OK
127.0.0.1:6379> get money
"1000"
127.0.0.1:6379> 

  此时小王的汇款也结束了,(执行了EXEC)

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET money 100
QUEUED
127.0.0.1:6379> EXEC
1) OK
127.0.0.1:6379> get money
"100"
127.0.0.1:6379> 

  平白无故丢了一千大洋,还得上十年学,十个暑假才能赚回来这些钱,很心塞。小王的问题也有办法解决,那就是在redis 2.2及以后版本之后引入的WATCH命令

  小王再次存钱卡主

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> WATCH money    ### 监控money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set money 100
QUEUED

  小王的妈妈依然是去银行转钱给小王,效率依然杠杠的

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set money 1000
QUEUED
127.0.0.1:6379> EXEC
1) OK
127.0.0.1:6379> get money
"1000"
127.0.0.1:6379> 

  小王存的钱开始被写入

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> WATCH money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set money 100
QUEUED
127.0.0.1:6379> EXEC
(nil)
127.0.0.1:6379> get money
"1000"
127.0.0.1:6379> 

  小王存钱没有成功,查看了下余额,发现已经有1000大洋了,那么这一百块就可以去挥霍了,吃饱喝足,网吧包夜走起。。。

  WATCH命令是一种乐观锁的实现,基于CAS(check and set,在java的JUC下atomic中,一些Atomic开头的类,也使用了CAS原理,只不过在java中被称为compare and set,但大致意思是一样的)。watch用于监控某个key是否发生了改变,如果在一个事务中,某个key在设置参数之后,在执行exec之前,其他客户端修改了该key,则该事务将返回null。

  1、watch必须与multi一起使用,才会发生作用,并且其必须在multi之前执行

  2、watch监控的元素在当前事务提交之前发生变化(另一个事务执行了exec),则无论当前事务中有多少命令,全部失败。

  3、watch监控的元素在当前事务提交之前,被放入到另外一个事务的队列中,但并未执行exec,则当前事务可正常提交

  4、watch监控的元素,被另外一个客户端在非MULTI包括的命令中修改,则无论当前事务中有多少命令,也将全部失败

 

Redis事务

标签:atom   服务   原理   字符串类   简单   就是   redis事务   redis命令   问题   

原文地址:https://www.cnblogs.com/qq931399960/p/10556699.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!