1. 事务
事务提供了一种“将多个命令打包, 然后一次性、按顺序地执行”的机制, 并且事务在执行的期间不会主动中断 —— 服务器在执行完事务中的所有命令之后, 才会继续处理其他客户端的其他命令。
Redis 通过 MULTI、DISCARD、EXEC和WATCH四个命令来实现事务功能,MULTI表示事务的开始;事务期间的命令并不会立刻执行,而是会进入命令队列,等待执行;EXEC表示事务的执行和结束,它会将队列中的命令依次执行;DISCARD表示丢弃事务;WATCH表示监听任意数量的key,当EXEC前发现key发现变化,就会直接返回失败。
当EXEC的过程中,如果有一个命令出错,不会影响后续命令的执行,只会将错误信息包在结果中返回。Redis事务不提供回滚的功能。
Redis的事务是原子性的。Redis基于单线程模型,且一个事务的多个命令会顺序执行,中间不会有其它命令插队。
2. pipeline
Redis的pipeline功能在命令行中没有,但redis是支持pipeline的。可以选择事务执行或者非事务方式。
import redis
redis.Redis.pipeline()
with r.pipeline(transaction=True) as p:
p.set("1", "1")
p.hgetall("1")
p.set("2", "2")
p.execute(raise_on_error=False)
需要说明的是,无论是否事务,这里的raise_on_error只代表再程序中是否抛出异常,但是在redis中,即使第2个命令出错了,也不影响后续的命令执行。
3. redis+lua
Redis内置lua解释器,可以执行lua脚本,可以实现复杂的逻辑。另外,比较重要的一点是,lua脚本的执行是原子的。
语法:
EVAL script numkeys key [key ...] arg [arg ...]
例如:
> eval "return 10" 0
(integer) 10
如果lua脚本比较大,每次都传输完整的脚本就不怎么划算了。可以使用SCRIPT LOAD命令,加载lua脚本到redis中,该命令返回给定脚本的SHA1校验和,可以用EVALHASH命令和这个校验和执行lua脚本。
以下是redis-py github文档上给的一个例子,实现了乘法功能。
>>> r = redis.Redis()
>>> lua = """
... local value = redis.call('GET', KEYS[1])
... value = tonumber(value)
... return value * ARGV[1]"""
>>> multiply = r.register_script(lua)
>>> r.set('foo', 2)
>>> multiply(keys=['foo'], args=[5])
10
在lua脚本中有call和pcall两种调用redis命令的方式,二者唯一区别是:当call在执行命令的过程中发生错误时,脚本会停止执行,并返回一个脚本错误,错误的输出信息会说明错误造成的原因;pcall出错时并不引发错误,而是返回一个带err域的lua表(table),用于表示错误。
4. codis
Codis是一个分布式 Redis 解决方案,但是不支持很多命令。以上所说的MULTI、DISCARD、EXEC和WATCH,以及SCRIPT都不支持。在使用pipeline时,不支持事务。但是支持EVAL和EVALHASH,不过要求其中操作的key属于同一个slot。
另外说一句,不同的key写入同一个slot可以用hashtag来实现