ACID 中关于原子性的定义:
原子性:一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
Redis事务不支持传统意义上的原子性,但可以通过Lua脚本来实现类似的功能。
事务测试
使用事务可能会遇到以下两种错误:
- 事务在执行 EXEC 之前,入队的命令可能会出错。比如,命令可能会产生语法错误(参数数量错误,参数名错误等),或者其他更严重的错误,比如内存不足(如果服务器使用 maxmemory 设置了最大内存限制的话)。
- 命令可能在 EXEC 调用之后失败。比如,事务中的命令可能处理了错误类型的键,比如将列表命令用在了字符串键上面,诸如此类。
测试:
- 第一种情况,语句格式语法错误,命令入队时就出错
127.0.0.1:6379> multi OK 127.0.0.1:6379> hset test:hash id 10 QUEUED 127.0.0.1:6379> hset test:hash name zhangsan QUEUED 127.0.0.1:6379> hset test:hash (error) ERR wrong number of arguments for 'hset' command 127.0.0.1:6379> exec (error) EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> hgetall test:hash (empty list or set) 127.0.0.1:6379>
可以看到这种情况在最后执行exec命令的时候提示事务错误,而且查看上面的的hash结构并没有设置成功。
- 第二种情况,命令入队时成功,执行时失败
127.0.0.1:6379> multi OK 127.0.0.1:6379> set a 1 QUEUED 127.0.0.1:6379> set b 2 QUEUED 127.0.0.1:6379> set c 3 QUEUED 127.0.0.1:6379> exec 1) OK 2) OK 3) OK 127.0.0.1:6379> get a "1" 127.0.0.1:6379> get b "2" 127.0.0.1:6379> get c "3" 127.0.0.1:6379> multi OK 127.0.0.1:6379> set a 11 QUEUED 127.0.0.1:6379> lpush b 22 22 33 44 QUEUED 127.0.0.1:6379> set c 33 QUEUED 127.0.0.1:6379> exec 1) OK 2) (error) WRONGTYPE Operation against a key holding the wrong kind of value 3) OK 127.0.0.1:6379> get a "11" 127.0.0.1:6379> get b "2" 127.0.0.1:6379> get c "33"
可以看到“lpush b 22 22 33 44”命令的“set 前后“a 11”、“set c 33”都执行成功了
对于 EXEC 执行之前的错误,Redis 会检查出来并返回错误自动放弃事务;但对于在 EXEC 调用后执行失败的情况,该条语句会执行失败,但事务中的其他命令仍会执行。
因此严格来说,Redis 事务确实不具备原子性的特征。
为什么Redis不支持回滚
如果有使用关系式数据库的经验, 那么 “Redis 在事务失败时不进行回滚,而是继续执行余下的命令”这种做法可能会觉得有点奇怪。
以下是这种做法的优点:
- Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
- 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。
鉴于没有任何机制能避免程序员自己造成的错误, 并且这类错误通常不会在生产环境中出现, 所以 Redis 选择了更简单、更快速的无回滚方式来处理事务。
Redis的设计哲学与性能考虑
- 简单与快速:Redis的设计理念是简单且快速。为了实现这一目标,Redis的内部结构被设计得相对简单。如果支持回滚机制,将增加Redis的复杂性和性能损耗,这与Redis的设计哲学不相符合。
- 避免不必要的开销:在Redis中,命令只会因为错误的语法或类型不匹配而失败,这些错误应该在开发过程中被发现,而不应该出现在生产环境中。因此,Redis选择了不支持回滚来避免不必要的开销。
总结来说,Redis 的事务在 EXEC 调用前出错会取消整个事务,但在 EXEC 调用后,即使某个命令执行失败,事务中的其他命令仍然会继续执行。
标签:事务,127.0,错误,0.1,Redis,redis,原子,6379 From: https://www.cnblogs.com/beatle-go/p/18104499