A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 小江哥 于 2018-5-29 10:33 编辑

概述

redis中的事务是一组命令的集合。事务同命令一样都是redis的最小执行单元。一个事务中的命令要么都执行,要么都不执行。

命令

1.以下是一个事务的例子,它先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令:

[Java] 纯文本查看 复制代码
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"
QUEUED
127.0.0.1:6379> GET book-name
QUEUED
127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"
QUEUED
127.0.0.1:6379> SMEMBERS tag
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) "Mastering C++ in 21 days"
3) (integer) 3
4) 1) "Mastering Series"
   2) "C++"
   3) "Programming"


事务错误
如果一个事务中的某个命令出现错误,redis的处理分为以下两种方式:
(1)语法错误。语法错误指命令不存在或者命令参数的个数不对

[Java] 纯文本查看 复制代码
127.0.0.1:6379> SET key1 hello
OK
127.0.0.1:6379> SET key2 world
OK
127.0.0.1:6379> MULTI 
OK
127.0.0.1:6379> SET key2 world1
QUEUED
127.0.0.1:6379> SET key1 
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> MGET key1 key2
1) "hello"
2) "world"


当出现语法错误时,redis会直接返回错误,连语法正确的命令也不会执行。

(2)运行错误。运行错误指在命令执行时出现的错误。

[Java] 纯文本查看 复制代码
127.0.0.1:6379> SET key1 hello 
OK
127.0.0.1:6379> SET key2 world
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET key1 hello1
QUEUED
127.0.0.1:6379> SADD key2 3
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> MGET key1 key2
1) "hello1"
2) "world"


如果redis的事务中出现了部分命令运行错误,其余正确的命令还是会被执行。

redis的事务没有关系数据库的回滚(rollback)功能。因此程序员需要自己实现回滚功能。

2.取消事务

DISCARD

DISCARD用于取消事务,放弃执行事务块内的所有命令,总是返回OK。

[Java] 纯文本查看 复制代码
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> PING
QUEUED
127.0.0.1:6379> SET greeting "hello"
QUEUED
127.0.0.1:6379> DISCARD
OK


3.带WATCH的事务
设想如下的场景:李四和王五两个人同时购票,李四的账户有200元,王五的账户有500元,票价为100元。

[Java] 纯文本查看 复制代码
127.0.0.1:6379> SET ticket 1
OK
127.0.0.1:6379> SET lisi 200
OK
127.0.0.1:6379> SET wangwu 500
OK


现在假如李四购票,需要从总票数ticket减1,然后再从李四的账户上扣款100元,这两个命令组成一个事务。

[Java] 纯文本查看 复制代码
127.0.0.1:6379> MULTI 
OK
127.0.0.1:6379> DECR ticket
QUEUED
127.0.0.1:6379> DECRBY lisi 100
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 0
2) (integer) 100
127.0.0.1:6379> MGET ticket lisi
1) "0"
2) "100"


假如在李四执行MULT到EXEC之间,王五已经完成了购票,总票数已经为0,此时再执行李四的购票操作则会出现逻辑错误。

[Java] 纯文本查看 复制代码
127.0.0.1:6379> MULTI 
OK
127.0.0.1:6379> DECR ticket 
QUEUED
127.0.0.1:6379> DECRBY lisi 100
QUEUED
127.0.0.1:6379> EXEC
1) (integer) -1
2) (integer) 100
127.0.0.1:6379> MGET ticket lisi
1) "-1"
2) "100"
#在MUTI和EXEC之间王五执行了DECR ticket


我们看到李四的购票后ticket等于-1,这肯定不符合逻辑。为了解决以上问题,redis提供了WATCH命令。

WATCH 命令用于在事务开始之前监视任意数量的键: 当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败。

此时李四的购票操作如下:

[Java] 纯文本查看 复制代码
127.0.0.1:6379> WATCH ticket 
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECR ticket 
QUEUED
127.0.0.1:6379> DECRBY lisi 100
QUEUED
127.0.0.1:6379> EXEC
1) (integer) 0
2) (integer) 100


假如在MULTI和EXEC之间,王五来抢票则会导致整个事务失败。

[Java] 纯文本查看 复制代码
127.0.0.1:6379> WATCH ticket
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECR ticket
QUEUED
127.0.0.1:6379> DECRBY lisi 100
QUEUED
127.0.0.1:6379> EXEC
(nil)
127.0.0.1:6379> MGET ticket lisi
1) "0"
2) "200"
#在MULTI和EXEC之间王五执行了DECR ticket


我们可以看到在ticket被修改后,李四的购票操作实际上没有执行。总票数和李四的总金额都是正常的。

4.取消WATCH

UNWATCH

Unwatch 命令用于取消 WATCH 命令对所有 key 的监视,总是返回OK。

[Java] 纯文本查看 复制代码
127.0.0.1:6379> WATCH lock lock_times
OK
127.0.0.1:6379> UNWATCH
OK

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马