redis事物

Redis使用MULTI, EXEC, DISCARD 和 WATCH 命令来实现事务功能。事务可以一次执行多个命令,并带有两个重要的保证:

1. 隔离性;顺序性

事务中的所有命令都被序列化按顺序执行。Redis执行事务期间,不会被其它客户端发送的命令打断,事务中的所有命令都作为一个隔离操作顺序执行。事务的执行顺序,取决于exec命令执行的顺序;

  • 我们先开启一个事务(A),执行set k1 aaa; get k1 aaa
  • 然后再创建一个事务(B), 执行get k1 ;
  • A事务执行 del k1
  • 先触发A事物执行, 再触发B事物执行
    预期结果
    我们认为redis是单线程的,所以执行顺序应该是:set k1 aaa; get k1;get k1; del k1, A和B事物都可以获取到k1的值;
    实际操作:
    redis事物_第1张图片

redis事物_第2张图片
实际上会发现,B事物并没有获取到k1的值,因为事物执行的隔离性, 因为我们先触发的A事物执行, 再触发的B事物执行,redis会对事物按触发exec的时间排序, 执行完一个事物在执行下一个事物;所以执行过程就是,先执行A事物(set k1 aaa,get k1,del k1),然后执行B事物(get k1);

2. 原子性

Redis事务是原子操作,或者执行所有命令或者都不执行。 EXEC 命令触发一个事务中所有命令的执行,所以,如果一个客户端断在调用EXEC 命令前丢失连接,那么所有的命令不会被执行,相反,如果EXEC 被调用,那么所有命令会被执行。当使用 AOF(append-only file) 方式持久化时,Redis使用单个 write(2) 系统调用将事务写到磁盘上。但是,如果Redis服务器崩溃或被系统管理员以某种硬方式杀死,则可能只注册了部分操作。Redis重启的时候会检测到这种情况,并返回错误退出。使用 redis-check-aof 工具可以删除部分事务,这样Redis可以重新启动

WATCH 命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行。
UNWATCH命令用于取消 WATCH 命令对所有 key 的监视。
DISCARD 命令取消事务,放弃执行事务队列内的所有命令,恢复连接为非 (transaction) 模式。
如果正在使用 WATCH 命令监视某个(或某些) key,那么取消所有监视,等同于执行命令 UNWATCH 。

验证:

  • 首先我们在Redis中创建k1
  • 开启A事物,执行命令 get k1; set k1 bbb; get k1
  • 监听k1(watch k1) ,开启B事物,get k1 ,del k1
  • 触发A事物执行全部命令
  • 触发B事物执行全部命令

预期结果: A事物全部执行成功;B事物输出bbb, 和ok
redis事物_第3张图片
redis事物_第4张图片
结果:B事物返回nil, 说明B事物没有执行, 我们开启对K1的监听后,B事物只要发现K1改变,就会放弃B事物的执行

UNWATCH命令只有在开启事物之前执行,才会起到作用

redis事物_第5张图片

3.为什么Redis不支持回滚?

如果你了解关系数据库,那么Redis事务处理机制看起来有点奇怪。
Redis事务中的命令允许失败,但是Redis会继续执行其它的命令而不是回滚所有命令。
这么做的原因有两点:

1. Redis 命令只在两种情况失败:

  • 语法错误的时候才失败(在命令输入的时候不检查语法)。
  • 要执行的key数据类型不匹配:这种错误实际上是编程错误,这应该在开发阶段被测试出来,而不是生产上。

2. 因为不需要回滚,所以Redis内部实现简单并高效。

当出现bug的时候Redis的这种做法并不友好,可是需要注意的是回滚并不能解决程序bug。
例如,对于需要增加1的逻辑增加了2,或者操作的key类型不对,这些情况回滚并没有什么帮助。
考虑到没有人能避免程序员错误,并且这种错误也基本不能进入生产环境,我们选择了更简单且更高效的方法,不支持错误回滚。

你可能感兴趣的:(redis,java,spring,cloud,spring)