跟我一起学Redis之Redis事务简单了解一下

前言关系数据库中的事务 , 小伙伴们应该是不陌生了 , 不管是在开发还是在面试过程中 , 总有两个问题逃不掉:

  • 说说事务得特性;
  • 事务隔离级别是怎么一回事?
事务处理不好 , 数据就可能不准确 , 最终就会导致业务出问题;借此机会简单回顾一下事务特性及其隔离级别 , 就当是复习了;
事务特性(ACID)
  • 原子性(Atomicity) 指事务内所有操作要么一起执行成功 , 要么都一起失败(或者说是回滚);如事务经典转账案例:A给B转账 , A把钱扣了 , 但B没有收到;可见这种错误是不能接受的 , 最终会回滚 , 这也是原子性的重要性 。
  • 一致性(Consistency) 指事务执行前后的状态一致 , 如事务经典转账案例:A给B互相转账 , 不管怎么转 , 最终两者钱的总和还是不变;
  • 持久性(Durability) 指事务一旦提交 , 数据就已经永久保存了 , 不能再回滚;
  • 隔离性(Isolation) 指多个并发事务之间的操作互不干扰 , 但是事务的并发可能会导致数据脏读、不可重复读、幻读问题 , 根据业务情况 , 采用事务隔离级别进行对应数据读问题处理 。
事务隔离级别
  • 都未提交(Read uncommitted) 指一个事务读取到其他未提交事务的数据 。 可能导致数据脏读 。转账案例:A正在给B转账 , 本来转的1000 , A多输入了个0 , 变成10000 , 但此事务还未提交 , 但此时B查询到转入的是10000 , 但A取消事务回滚之后 , B又查询不到转入的数据 。 这种情况就是脏读
  • 都已提交(Read committed) 指一个事务只能读取到其他事务已提交的数据 , 从而解决了脏读的问题 。 但可能导致数据不可重复读; 转账案例:A要给B转账1000 , A先查看了一下余额 , 有1000 , 然后开始给B转钱 , 但此时A家里电费通过开启的自动缴费功能 , 自动从A账户扣除200缴纳电费 , 并提交;当A转账准备提交 , 再次确认余额时 , 钱少了200 。 这样就导致同一个事务中多次查询的结果不一致 , 这种情况就是不可重复读;
  • 可重复读(Repeatable read) 指事务只要一开启 , 就不允许其他事务进行修改操作 , 从而解决了不可重复读问题 。 但可能导致数据幻读; 转账案例:A经常给B转账 , 到年底了 , 需要查账 , 然后开启了一个事务进行查询统计 , 刚开始查询只是10条转账记录 , 正准备统计时 , 因为紧急情况A需要给B转一笔钱应急 , 从而新增了一条新记录 , 并提交;而查账事务正在统计中 , 最后发现转账额和看到的10条转账记录不匹配 。 这种情况就是幻读
  • 序列化(Serializable ) 指事务之间只能串行话执行 , 就像队列一样 , 排队进行 , 这样就解决了幻读的问题 , 但是这种级别的并发性能不高 , 非特殊需求 , 这种级别一般不用 。
正文转入正题 , 结合关系型数据库的事务来看看Redis中事务有什么不同;
Redis事务是指将多条命令加入队列 , 一次批量执行多条命令 , 每条命令会按顺序执行 , 事务执行过程中不会受客户端传入的命令请求影响 。
Redis事务的相关命令如下:
  • MULTI:表示一个事务的开启 , 即开启事务;
  • EXEC:执行事务中的所有命令 , 即提交;
  • DISCARD:放弃事务;和回滚不一样 , Redis事务不支持回滚 。
  • WATCH:监视Key改变 , 用于实现乐观锁 。 如果监视的Key的值改变 , 事务最终会执行失败 。
  • UNWATCH:放弃监视 。
Redis事务和关系型数据库的事务不太一样 , 它不保证原子性 , 也没有隔离级别的概念 。 来 , 结合命令演示 , 实战说明一切:
没有隔离级别:
跟我一起学Redis之Redis事务简单了解一下文章插图
如上图所示 , 当事务开启时 , 事务期间的命令并没有执行 , 而是加入队列 , 只有执行EXEC命令时 , 事务中的命令才会按照顺序一一执行 , 从而事务间就不会导致数据脏读、不可重复读、幻读的问题 , 因此就没有隔离级别 。
不保证原子性:
跟我一起学Redis之Redis事务简单了解一下文章插图
如上图所示 , 在通过EXEC执行事务时 , 其中命令执行失败不会影响到其他命令的执行 , 并没有保证同时成功和同时失败的原子操作 , 尽管这样 , Redis事务中也没有提供回滚的支持 , 官方提供了两个理由:
跟我一起学Redis之Redis事务简单了解一下文章插图
大概的意思就是: