Redis学习二:事务

1.Redis事务的特点

redis的事务与RDB的事务不同,具有如下特点:

  • 满足隔离性:客户端提交命令到队列,服务端按顺序执行,事务在执行过程中不会被其他客户端打断。
  • 原子性:事务中的命令要么全部执行,要么全部不执行。但是若执行过程中某一条命令发生错误,其他命令依然能成功执行。(与我们所理解的ACID中原子性不太一样,RDB的原子性强调的是要么全部成功,要么全部失败)

Redis原子性之所以与ACID的原子性不一样的原因,是由于Redis不支持回滚。官网对于不支持回滚的解释:
通常情况下, 回滚并不能解决编程错误带来的问题。 举个例子, 如果你本来想通过 INCR 命令将键的值加上 1 , 却不小心加上了 2 , 又或者对错误类型的键执行了 INCR , 回滚是没有办法处理这些情况的。,不支持回滚还有如下的优点:

  • Redis命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
  • 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。

2. 相关命令

  • MULTI:开启事务。MULTI 执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中。
  • EXEC:提交事务。调用EXEC后才会真正执行队列中的命令。(注意:若队列中某个命令存在语法错误,若seta b,明显seta是个不能存在的操作,这时候调用EXEC队列中的所有命令都不会执行,这不是因为原子性,而是一种类似于代码编译错误的错误导致所有命令都不会执行。)
  • DISCARD:放弃事务。清空任务队列并放弃事务
  • WATCH:监视一个或多个key的变更。若被监视的key在 EXEC 执行之前被修改了, 那么整个事务都会被取消。
  • UNWATCH:手动取消对所有key的监视。如果执行EXEC 或者DISCARD, 则不需要手动执行UNWATCH。

3. check-and-set(CAS)

即WATCH命令的底层实现,为Redis事务提供乐观锁,类似JUC的compareAndSwap。WATCH命令一遇到其他客户端修改所监视的key事务就失败。但是通常我们需要一个事务被成功且正确的执行,可以采用如下的办法:

  • 与compareAndSwap一样,不断循环watch multi exec 这个过程。
  • 使用分布式锁,将乐观锁改为悲观锁实现。

4. 并发场景下的解决办法

有时候业务场景复杂,并不是并发的set某个key那么简单,例如:
对某个涉及高并发修改的key,需要判断key的value为多少,去决定怎么修改该key。此时使用事务很难达到效果,因为redis的事务特性相当于是批量提交命令再批量执行,提交命令入队过程中命令并没有真正执行,此时无法准确获取key的值做判断。
可采用Lua脚本解决。
Redis 中的脚本本身就是一种事务, 所以任何在事务里可以完成的事, 在脚本里面也能完成。

发布了26 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_36142042/article/details/104858376
今日推荐