返回 导航

大数据

hangge.com

Redis - 事务机制详解(附样例)

作者:hangge | 2025-01-20 09:23
    Redis 也支持事务,可以一次性、顺序性、排他性地执行一个队列中的一系列命令。但是 redis 的事务不并不是完整意义上的事务,我们称之为弱事务。因为 redis 中并没有事务回滚机制。下面我将通过样例进行演示。

1,Redis 事务的三个特性

  • 单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在“事务内的查询要看到事务里的更新,在事务外查询不能看到”这个问题
  • 不保证原子性redis 同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。

2,事务命令

(1)开启事务:MULTI
  • 用于标记事务块的开始。Redis 会将后续的命令逐个放入队列中,然后才能使用 EXEC 命令原子化地执行这个命令序列。

(2)执行事务:EXEC
  • 在一个事务中执行所有先前放入队列的命令,然后恢复正常的连接状态。当使用 WATCH 命令时,只有当受监控的键没有被修改时,EXEC 命令才会执行事务中的命令,这种方式利用了检查再设置(CAS)的机制

(3)取消事务:DISCARD
  • 清除所有先前在一个事务中放入队列的命令,然后恢复正常的连接状态。如果使用了 WATCH 命令,那么 DISCARD 命令就会将当前连接监控的所有键取消监控。

(4)对指定 key 添加监视锁:WATCH
  • 当某个事务需要按条件执行时,就要使用这个命令将给定的键设置为受监控的。在执行 exec 前如果该 key 发生了变化,终止事务执行。

(5)取消对所有 key 的监视:UNWATCH
  • 清除所有先前为一个事务监控的键。

3,事务使用样例

(1)下面是一个开启事务和取消事务的例子:
# 设置count值
SET count 1

# 读取count值
GET count

#开启事务
MULTI

#发送事务的第一个操作,对count减1
DECR count

#执行DISCARD命令,主动放弃事务
DISCARD

#再次读取count的值,值没有被修改
GET count


(2)运行结果如下,可以看到由于我们取消了事务,因此事务中对 count 的操作是没有执行,count 的值不会发生改变。

4,Redis 事务不支持回滚

(1) Redis 事务并不一定保证原子性,事务执行过程中,如果命令入队时没报错,而事务提交后,实际执行时报错了,正确的命令依然可以正常执行。比如下面事务中我们故意写了一条执行时会出现错误的命令:
原子性:事务中的命令要不全部成功,要不全部失败。
# 设置count值
SET count 1
 
# 读取count值
GET count
 
# 开启事务
MULTI
 
# 发送事务的第一个操作,对count减1
DECR count

# 发送事务的第二个操作,运行时会错误的命令(过期时间正确来说是数字,并不是‘10s’字符串)
EXPIRE count 10s
 
# 执行事务
EXEC
 
# 再次读取count的值,值没有被修改
GET count
不支持回滚原因:
  • Redis 作者认为 Redis 事务的执行时,错误通常都是编程错误造成的,这种错误通常只会出现在开发环境中,而很少会在实际的生产环境中出现,所以他认为没有必要为 Redis 开发事务回滚功能;
  • 不支持事务回滚是因为这种复杂的功能和 Redis 追求的简单高效的设计主旨不符合。

(2)要注意的是,不支持事务回滚,指的是不支持事务运行时错误的事务回滚。语法错误导致事务执行异常,该事务取消。如果语法错误导致事务执行异常,该事务会取消。比如我们在事务中写了一条语法错误的命令:
# 设置count值
SET count 1
 
# 读取count值
GET count
 
# 开启事务
MULTI
 
# 发送事务的第一个操作,对count减1
DECR count

# 发送事务的第二个操作,语法错误命令
SETTT test 2222
 
# 执行事务
EXEC
 
# 再次读取count的值,值没有被修改
GET count
评论

全部评论(0)

回到顶部