Redis笔记(五)之事务

redis版本

  1. redis版本:3.2.11

事务

  1. 在关系型数据库中,事务表示一组动作,要么全部执行,要么全部不执行。Redis提供了简单的事务功能,Redis保证一个事务中的所有命令要么都执行,要么都不执行。而一旦客户端发送了EXEC命令,所有的命令就都会被执行,即使此后客户端断线也没关系,因为Redis中已经记录了所有要执行的命令。

  2. 事务图解

    image-20190316201444415

事务命令

  1. MULTI:标记一个事务块的开始,总是返回OK。事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性(atomic)地执行

  2. DISCARD(丢弃):取消事务,放弃执行事务块内的所有命令。如果正在使用 WATCH 命令监视某个(或某些) key,那么取消所有监视,等同于执行命令 UNWATCH

  3. EXEC:执行事务块内的所有命令。假如某个(或某些) key 正处于 WATCH 命令的监视之下,且事务块中有和这个(或这些) key 相关的命令,那么EXEC命令只在这个(或这些) key 没有被其他命令所改动的情况下执行并生效,否则该事务被打断(abort)。如果客户端在使用MULTI开启一个事务之后,因为断线而没有成功执行EXEC,那么事务中的所有命令都不会执行。如果客户端在成功开启事务之后执行EXEC,则事务中的所有命令都会被执行。

  4. WATCH:

    • WATCH可以监控一个或者多个key,一旦其中有一个key在EXEC执行之前被修改(或者删除),那么整个事务都会被取消,EXEC返回空多条批量回复(null multi-bulk reply)来表示事务已经失败。WATCH一直持续到EXEC命令(事务中的命令是在EXEC之后才执行的,所以在MULTI命令后可以修改WATCH监控的key)
    • WATCH可以为Redis事务提供check-and-set(CAS)行为
  5. UNWATCH:取消WATCH命令对所有key的监视。如果在执行WATCH命令之后,EXEC命令或DISCARD命令先被执行了的话,那么就不需要再执行UNWATCH了。因为EXEC命令会执行事务,因此WATCH命令的效果已经产生了。而DISCARD命令在取消事务的同时也会取消所有对key的监视,因此这两个命令执行之后,就没有必要执行UNWATCH

乐观锁

  1. 从下面的例子可以看出【客户端1】的事务并没有执行成功,而是执行失败了,因为【客户端2】在【客户端1】执行EXEC之前修改了key的值导致【客户端1】的事务被中断。

    客户端1客户端2
    127.0.0.1:6379> WATCH count
    OK
    127.0.0.1:6379> get count
    (integer) 1
    127.0.0.1:6379> incr count
    (integer) 2
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> incr count
    QUEUED
    127.0.0.1:6379> EXEC
    (nil)
    127.0.0.1:6379> get count
    “2”
  2. 如果在WATCH执行之后,EXEC执行之前, 有其他客户端修改了key的值,那么当前客户端的事务就会失败。程序需要做的,就是不断重试这个操作,直到没有发生碰撞为止

  3. Redis禁止在MULTIEXEC之间执行WATCH命令,而必须在MULTI之前执行WATCH命令,WATCH命令可以被调用多次

  4. 如果你使用WATCH监视了一个带过期时间的键, 那么即使这个键过期了, 事务仍然可以正常执行

        0. 准备过期的key
        127.0.0.1:6379> set username jannal
        OK
        127.0.0.1:6379> EXPIRE username 60
        (integer) 1
        127.0.0.1:6379> ttl username
        (integer) 56
        
        1. 监控一个过期的key
        127.0.0.1:6379> WATCH username
        OK
        127.0.0.1:6379> get username
        "jannal"
        
        127.0.0.1:6379> MULTI
        OK
        2. 等待key过期之后再执行这个命令
        127.0.0.1:6379> set username jack
        QUEUED
        127.0.0.1:6379> EXEC
        1) OK
        
        3. 发现事务执行成功,并且没有过期时间了
        127.0.0.1:6379> get username
        "jack"
        127.0.0.1:6379> ttl username
        (integer) -1
    
    

事务执行错误模拟

命令错误

  1. 比如将set写成sett,这属于语法错误,会造成整个事务无法执行

        1. 准备数据
        127.0.0.1:6379> set username jannal
        OK
        127.0.0.1:6379> incr count
        (integer) 1
        127.0.0.1:6379> mget username count
        1) "jannal"
        2) "1"
        
        2. 开启事务
        127.0.0.1:6379> multi
        OK
        127.0.0.1:6379> sett username jack
        (error) ERR unknown command 'sett'
        127.0.0.1:6379> incr count
        QUEUED 表示被服务器缓存到队列里了
        127.0.0.1:6379> exec
        (error) EXECABORT Transaction discarded because of previous errors.
        
        3. 发现username和count的值都为发生变化
        127.0.0.1:6379> mget username count
        1) "jannal"
        2) "1"
    
    
    

运行时错误

  1. 比如类型错误,比如对字符串进行数学运算

        1. 查看执行之前的数据
        127.0.0.1:6379> mget username count
        1) "jannal"
        2) "1"
        
        2.开启事务
        127.0.0.1:6379> multi
        OK
        127.0.0.1:6379> set username jack
        QUEUED
        127.0.0.1:6379> incr username
        QUEUED
        127.0.0.1:6379> incr count
        QUEUED
        127.0.0.1:6379> exec
        1) OK
        2) (error) ERR value is not an integer or out of range
        3) (integer) 2
        
        2. 发现事务运行时发生错误,但是后续的incr还是执行成功了
        127.0.0.1:6379> mget username count
        1) "jack"
        2) "2"
    

持久化

  1. 当使用AOF方式做持久化的时候,Redis会使用单个 write(2) 命令将事务写入到磁盘中。然而,如果 Redis 服务器因为某些原因被管理员杀死,或者遇上某种硬件故障,那么可能只有部分事务命令会被成功写入到磁盘中。如果 Redis 在重新启动时发现 AOF 文件出了这样的问题,那么它会退出,并汇报一个错误。使用redis-check-aof程序可以修复这一问题:它会移除 AOF 文件中不完整事务的信息,确保服务器可以顺利启动。

总结

  1. Redis中的事务仅仅满足了事务不被其他事务打断的权利。Redis的事务没有关系数据库事务提供的回滚(rollback)功能。由于Redis不支持回滚功能,也使得Redis在事务上可以保持简洁和快速。不支持回滚的原因是因为导致redis事务执行失败的两种错误就是命令错误和运行时错误,即只有程序错误才会导致Redis命令执行失败,而这两种错误在生产环境下都不应该出现(在开发和测试阶段会被发现)
  2. 其中语法错误完全可以在开发时找出并解决,另外如果能够很好地规划数据库(保证键名规范等)的使用,是不会出现如命令与数据类型不匹配这样的运行错误的

事务优化

  1. Redis事务在发送每一个指令的到事件队列时都要经过一次网络请求,当一个事务内部的指令较多时,需要的网络IO时间也会变长,所以通常Redis的客户端在执行事务时都会结合Pipeline一起使用,这样可以将多次IO操作压缩为单次IO操作
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值