Redis 支持原子性吗?


#Redis


结论:

  • 单个命令支持原子性。
  • 事务不支持原子性。
  • lua 脚本不支持原子性。
  • 因为 redis server 是在单线程中执行指令的,所以事务和lua满足最严格的隔离性。

在数据库事务的场景中,原子性是指多个操作要么全部执行,要么全部都不执行。

这里隐含了一个推论:如果事务中有一个指令报错,那么事务中的所有操作都应该不执行。

在 redis 事务或者lua脚本中,若遇到指令实行失败,之前已经执行成功的指令是不会回滚的,所有做不到全部不执行。

测试示例1: 事务

127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name xxx
QUEUED
127.0.0.1:6379> incr name
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) ERR value is not an integer or out of range
127.0.0.1:6379> get name
"xxx"

开始时 name 不存在,然后在事务中 set name xxx ,紧接着 incr name ,因为 name 的 value 不是数字,所以执行事务时 incr 报错。事务结束后发现 name 能获取到值。这说明事务没有回滚。

测试示例2: lua 脚本

127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> eval "redis.call('SET', 'name', 'xxx'); redis.call('INCR', 'name');" 0
(error) ERR Error running script (call to f_ae06c41c139281545d84cf8ea22d8d6d3721636b): @user_script:1: ERR value is not an integer or out of range
127.0.0.1:6379> get name
"xxx"

开始时 name 不存在,然后在lua脚本中 set name xxx ,紧接着 incr name ,因为 name 的 value 不是数字,所以执行lua脚本时 incr 报错。脚本执行完成后发现 name 能获取到值。这说明脚本执行也没有回滚机制。



( 本文完 )