美文网首页
关于redis事务的几点思考

关于redis事务的几点思考

作者: 高稚商de菌 | 来源:发表于2019-03-01 19:56 被阅读0次
    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来实现

    相关文章

      网友评论

          本文标题:关于redis事务的几点思考

          本文链接:https://www.haomeiwen.com/subject/tyujuqtx.html