Redis之事务

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis之事务



前言

Redis事务命令(开启事务、提交事务、取消事务、监视)、乐观锁、悲观锁。


一、概述

Redis事务的本质是一组命令的集合

事务支持一次执行多个命令,一个事务中所有命令都会被序列化。

在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。

所以说:Redis 事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。

事务支持一次执行多个命令,一个事务中所有命令都会被序列化。

批量操作在发送 EXEC 命令前被放入队列缓存,并不会被实际执行。

Redis 事务不保证原子性

Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。

事务中任意命令执行失败,其余的命令仍会被执行。

Redis事务的三个阶段

  • 开启事务
  • 命令入队
  • 执行事务

二、实例演示

1.正常执行事务

127.0.0.1:6379> multi  # 开启事务
OK
## 命令入队
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务
OK
OK
OK

2.取消事务

127.0.0.1:6379> multi # 开启事务
OK
# 命令入队
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> discard # 取消事务,事务队列中命令都不会执行
OK
127.0.0.1:6379> DBSIZE # 可以看出set命令未执行
0

3.编译型异常

若在事务队列中存在命令性错误(类似于java编译性错误),则执行 exec 命令时,所有命令都不会执行。

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> multi
OK
# 命令入队
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> getset k2 # 错误命令
ERR wrong number of arguments for 'getset' command
127.0.0.1:6379(TX)> set k3 v3  # 命令入队
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务,报错 ,所有命令都不执行
EXECABORT Transaction discarded because of previous errors.

4.运行时异常

若在事务队列中存在语法性错误(类似于 Java 的的运行时异常),则执行exec命令时,其他正确命令会被执行,错误命令抛出异常。

127.0.0.1:6379> set k1 v1 # k1的值为字符串,无法实现增减
OK
127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> incr k1 # 执行失败
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> exec 
ERR value is not an integer or out of range # 第一条命令报错,其他命令正常执行
OK
v2

5.监听

watch(乐观锁实现)

  • 悲观锁
    悲观锁(Pessimistic Lock),顾名思义,就是很悲观。
    每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁。
    这样别人想拿到这个数据就会 block 直到它拿到锁。
    传统的关系型数据库里面就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在操作之前先上锁。
  • 乐观锁
    乐观锁(Optimistic Lock),顾名思义,就是很乐观。
    每次去拿数据的时候都认为别人不会修改,所以不会上锁。
    但是在更新的时候会判断一下再此期间别人有没有去更新这个数据,可以使用版本号等机制。
    乐观锁适用于多读的应用类型,这样可以提高吞吐量。
    乐观锁策略:提交版本必须大于记录当前版本才能执行更新。

(1)事务过程未有数据改变

127.0.0.1:6379> set money 100 # 余额
OK
127.0.0.1:6379> set out 0 # 支出
OK
127.0.0.1:6379> watch money # 监视money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> DECRBY money 20 # 余额减20
QUEUED
127.0.0.1:6379(TX)> INCRBY out 20 # 支出金额多20
QUEUED
127.0.0.1:6379(TX)> exec # 提交事务,成功执行
1) (integer) 80
2) (integer) 20

(2)事务过程其他线程改变数据

利用多线程测试

窗口1:

127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> DECRBY money 10
QUEUED
127.0.0.1:6379(TX)> INCRBY out 10
QUEUED

窗口2:

127.0.0.1:6379> get money
"80"
127.0.0.1:6379> set money 200
OK

窗口1:

127.0.0.1:6379(TX)> exec # 事务提交,执行失败
(nil)

在窗口1事务提交前,窗口2修改了money的值。所以窗口1提交事务,执行失败。

解决:

窗口1:

127.0.0.1:6379> unwatch # 执行失败就先解除监听
OK
127.0.0.1:6379> watch money # 获取新值,重新监听,开启事务
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> DECRBY money 10
QUEUED
127.0.0.1:6379(TX)> INCRBY out 10
QUEUED
127.0.0.1:6379(TX)> exec # 提交事务,执行成功(对比监视的值是否发生变化,没有则执行成功,否则失败)
1) (integer) 190
2) (integer) 30

总结

  • 一旦执行exec开启事务后,无论事务是否执行成功, watch 对变量的监听都将被取消。
  • 当事务执行失败后,需重新执行 watch 命令对变量进行监听,并开启新的事务进行操作。
  • watch 指令类似于乐观锁,在事务提交时,如果 watch 监控的多个 key 中任何 key 的值已经被其他客户端更改。则使用 exec 执行事务时,事务队列将不会被执行,同时返回 (nil) 应答以通知调用者事务执行失败。
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
27天前
|
NoSQL Redis 数据库
什么是Redis的事务?
Redis事务提供原子性和顺序性,确保命令按顺序执行且不被打断。核心概念包括原子性、顺序性、隔离性和持久性。关键指令有MULTI、EXEC、DISCARD和WATCH,用于事务的开始、执行、取消和监视。这保障了命令的完整性,防止并发操作导致的数据不一致。
13 2
|
3月前
|
缓存 NoSQL 数据处理
Redis事务悄然而至:命令的背后故事
Redis事务悄然而至:命令的背后故事
27 0
|
4月前
|
缓存 监控 NoSQL
Redis之事务
【1月更文挑战第7天】Redis事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行!一次性、顺序性、排他性!执行一些列的命令。
169 1
|
4月前
|
消息中间件 移动开发 NoSQL
Redis 协议 事务 发布订阅 异步连接
Redis 协议 事务 发布订阅 异步连接
|
5月前
|
监控 NoSQL 关系型数据库
|
27天前
|
NoSQL Redis
Redis事务:保证数据操作的一致性和可靠性
Redis事务:保证数据操作的一致性和可靠性
|
6月前
|
监控 NoSQL Redis
【Redis 系列】redis 学习六,redis 事务处理和监控事务
【Redis 系列】redis 学习六,redis 事务处理和监控事务
|
5月前
|
监控 NoSQL Java
Redis数据库 | 事务、持久化
Redis数据库 | 事务、持久化
28 0
|
3月前
|
消息中间件 NoSQL Kafka
Redis事务与异步方式
Redis事务与异步方式
35 0
|
4月前
|
缓存 监控 NoSQL
腾讯二面:Redis 事务支持 ACID 么?
腾讯二面:Redis 事务支持 ACID 么?
72 0