===== Redis 事务操作 =====
Redis支持WATCH/MULTI/EXEC的事务操作(不完全是事务,因为即使有一条命令失败,不会导致全部失败)
* watch命令
* 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他会话所改动,那么事务将被打断
* MULTI命令
* 标记一个事务块的开始。事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性(atomic)地执行。
* EXEC
* 执行所有事务块内的命令。
* UNWATCH命令
* 取消 WATCH 命令对所有 key 的监视。如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行 UNWATCH 了。
* DISCARD
* 取消事务,放弃执行事务块内的所有命令。如果正在使用 WATCH 命令监视某个(或某些) key,那么取消所有监视,等同于执行命令 UNWATCH
===== lua脚本的原子性 =====
当Redis在运行Lua脚本的时候,其它的事情什么都干不了!脚本最好只是简单的扩展Redis进行较小的原子操作和简单的逻辑控制需要,Lua脚本中的bug可能引发整个Redis服务器锁—最好保持脚本的简短和易于调试。
Redis支持WATCH/MULTI/EXEC这样的块,能进行一组操作,也能一起提交执行,看起来与Lua有重叠。应该如何进行选择?
* MULT块中所有操作独立
* 但在Lua中,后面的操作能依赖前面操作的执行结果。同时使用Lua脚本还能够避免WATCH使用后竞争条件引起客户端反应变慢的情况。
在RedisGreen(译注:国外一家专门提供Redis主机的服务商),我们看到许多应用使用Lua的同时也使用MULTI/EXEC,但两者但不是替代关系。许多成功的Lua脚本都很小,仅仅实现一个你的应用需要而Redis命令中没有单一的功能。
===== 常见问题 =====
* 丢失更新问题,当多线程同时操作某个key时发生
* 解决方案:用lua脚本原子化,读取,处理,写回 三个操作
* 如果处理过程的命令相互独立(不依赖上一条命令的结果),那可以直接在程序中用mutil命令原子化一组操作
===== call和pcall =====
redis提供了一个lua的接口(主要是2个函数,call,pcall),但是在redis中使用lua脚本有诸多限制,主要是为了避免阻塞redis,毕竟redis是单线程,一旦阻塞就什么都不能做了。
==== call和pcall的区别 ====
* redis.call()
* 一旦出现异常,终止异常脚本,抛出异常
* redis.pcall()
* 一旦出现异常,返回一个异常对象,并继续执行。除非在lua脚本的最后显示return 异常对象,否则客户端(可能是你的java程序)无法捕获这个异常