赞
踩
事务表示一组动作,要么全部执行,要么全部不执行。例子如下。
Redis提供了简单的事务功能,讲一组需要一起执行的命令放到multi和exec两个命令之间。multi命令代表事务开始,exec命令代表事务结束,如果要停止事务的执行,可以使用discard命令代替exec命令即可。它们之间的命令是原子执行的
例如在社交网站上用户A关注了用户B,那么需要在用户A的关注表中加入用户B,并且在用户B的粉丝表中添加用户A,这两个行为要么全部执行,要么全部不执行,否则会出现数据不一致的情况
例如下面代码实现了用户关注问题
127.0.0.1:6379> SADD u:a:follow ub
QUEUED
127.0.0.1:6379> SADD u:b:fans ua
QUEUED
可以看到SADD命令此时的返回结果是QUEUED,代表命令并没有真正执行,而是暂时保存在Redis中的一个缓存队列(所以discard也只是丢弃这个缓存队列中的未执行命令,并不会回滚已经操作过的数据,这一点要和关系型数据库的Rollback操作区分开)。如果此时另一个客户端执行下方代码,返回结果应该是0
127.0.0.1:6379> SISMEMBER u:a:follow ub
(integer) 0
只有当exec执行后,用户A关注用户B的行为才算完成,如下所示exec返回的两个结果对应SADD命令
127.0.0.1:6379> multi
OK
127.0.0.1:6379> SADD u:a:follow ub
QUEUED
127.0.0.1:6379> SADD u:b:fans ua
QUEUED
127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 1
另一个客户端:
127.0.0.1:6379> SISMEMBER u:a:follow ub
(integer) 0
127.0.0.1:6379> SISMEMBER u:a:follow ub
(integer) 1
如果事务中的命令出现错误,Redis的处理机制也不尽相同
例如下面操作将set写成了SETT,属于语法错误,会造成整个事务无法执行,
127.0.0.1:6379> set txkey hello OK 127.0.0.1:6379> set txcount 100 OK 127.0.0.1:6379> mget txkey txcount 1) "hello" 2) "100" 127.0.0.1:6379> multi OK 127.0.0.1:6379> sett txkey world (error) ERR unknown command `sett`, with args beginning with: `txkey`, `world`, 127.0.0.1:6379> incr txcount QUEUED 127.0.0.1:6379> exec (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> mget txkey txcount 1) "hello" 2) "100"
例如用户B在添加粉丝列表时,误把SADD命令(针对集合)写成了ZADD命令(针对有序集合),这种就是运行时命令,因为语法时正确的:
127.0.0.1:6379> SADD u:b:fans ua
(integer) 1
127.0.0.1:6379> multi
OK
127.0.0.1:6379> SADD u:c:follow ub
QUEUED
127.0.0.1:6379> ZADD u:b:fans 1 uc
QUEUED
127.0.0.1:6379> exec
1) (integer) 1
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> sismember u:c:follow ub
(integer) 1
可以看到Redis并不支持回滚功能,SADD u:c:follow ub命令已经执行成功,开发人员需要自己修复这类问题。
有些应用场景需要在事务之前,确保事务中的key没有key没有被其他客户端修改过,才执行事务,否则不执行(类似乐观锁)。Redis提供了watch命令来解决这类问题。
客户端1
127.0.0.1:6379> set testwatch java
OK
127.0.0.1:6379> watch testwatch
OK
127.0.0.1:6379> multi
OK
客户端2
127.0.0.1:6379> get testwatch
"java"
127.0.0.1:6379> append testwatch python
(integer) 10
客户端1继续:
127.0.0.1:6379> append testwatch jedis
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get testwatch
"javapython"
可以看到客户端1在执行multi之前执行了watch命令,客户端2在客户端1执行exec之前修改了key值,造成可客户端1事务没有执行(exec结果为nil)
Redis在2.6推出了脚本功能,允许开发者使用Lua语言编写脚本传到Redis中执行,使用脚本的好处如下:
A Redis script is transactional by definition, so everything you can do with a Redis transaction, you can also do with a script,and usually the script will be both simpler and faster.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。