【Redis 系列】redis 学习六,redis 事务处理和监控事务

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 【Redis 系列】redis 学习六,redis 事务处理和监控事务

【Redis 系列】redis 学习六,redis 事务处理和监控事务

写在前面

我们学过的事务都是保证原子性的,但是 redis 的事务中执行多个指令,是不保证原子性的

redis 事务的本质

就是一组命令的集合,一个事务中所有的命令都会被序列化,在事务执行的过程,是按照顺序执行命令的,他们拥有

  • 一次性
  • 顺序性
  • 排他性

redis 的事务没有隔离级别的概念

redis 事务中,命令是这样执行的

命令放在事务中,并没有马上执行,而是发起执行命令的时候才会执行,通过 exec 触发

redis 是单条指令保证原子性,但是事务不保证原子性

执行一个事务的流程是这个样子的:

  • multi 开启事务
  • 各种命令入队
  • exec 执行事务

开启事务

MULTI

开启一个事务

EXEC

执行事务里面的指令

执行事务完毕后,需要再使用事务,那么需要再次开启事务

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 name xiaozhu
QUEUED
127.0.0.1:6379(TX)> set age 19
QUEUED
127.0.0.1:6379(TX)> set hobby paly
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
3) OK
4) OK
5) OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set city changsha
QUEUED
127.0.0.1:6379(TX)> get city
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) "changsha"

放弃事务

DISCARD

放弃最近开启的事务

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set name xiaozhu
QUEUED
127.0.0.1:6379(TX)> set age 10
QUEUED
127.0.0.1:6379(TX)> set city beijing
QUEUED
127.0.0.1:6379(TX)> DISCARD
OK
127.0.0.1:6379> get city
(nil)
127.0.0.1:6379> get name
(nil)

事务出错

事务出错分为两种:

  • 编译型出错
  • 运行时出错

编译型出错

代码编写出错,无法通过编译,此时事务里面编写的指令,全部执行失败

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set name xiaozhu
QUEUED
127.0.0.1:6379(TX)> set age 10
QUEUED
127.0.0.1:6379(TX)> set hobby play
QUEUED
127.0.0.1:6379(TX)> set city changsha
QUEUED
127.0.0.1:6379(TX)> set dream xxx
QUEUED
127.0.0.1:6379(TX)> setget hahaha  # 指令不存在,编译不通过,直接报错
(error) ERR unknown command `setget`, with args beginning with: `hahaha`,
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get city
(nil)

一旦编译出错,事务里面的所有指令都不会执行

运行时出错

程序运行时某一个指定的某个逻辑出现问题,仅仅影响本条执行的执行,并且本条指令会跑出异常,不影响事务中其他指令的执行

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set name xiaozhu
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> get name
QUEUED
127.0.0.1:6379(TX)> INCR name  # incr 指令用法正确,只不过 name 是字符串,运行的时候,是无法执行通过的
QUEUED
127.0.0.1:6379(TX)> set age 29
QUEUED
127.0.0.1:6379(TX)> set hobby play
QUEUED
127.0.0.1:6379(TX)> exec
1) "xiaozhu"
2) (error) ERR value is not an integer or out of range
3) OK
4) OK
127.0.0.1:6379> get hobby
"play"
127.0.0.1:6379> get name
"xiaozhu"

根据上述结果,incr 指令的用法正确,但是 incr 只能对数字进行操作,name 是一个字符串,无法做自增操作,因此运行时报错,事务中不影响其他的指令执行

redis 的 watch 监控

watch 监控,可以说说 乐观锁 和 悲观锁

乐观锁

  • 很乐观,认为什么时候都不会出问题,所以不会上锁,就更新数据的时候会去判断一下在此期间若数据发生了变化
  • 乐观锁会先获取一个基础数据版本
  • 更新数据的时候,会比较这个版本是否发生变化,若发生变化,则更新失败,若未发生变化,则更新数据

悲观锁

  • 很悲观,无论什么时候都认为会出问题,都要加锁

redis 的监控测试

用 watch 来加锁模拟银行取钱

  • money 账户 有 2000
  • outer 账户 有 500
  • money 账户 给 outer 账户 500
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> set money 2000
OK
127.0.0.1:6379> set outer 500
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> DECRBY money 500
QUEUED
127.0.0.1:6379(TX)> INCRBY outer 500
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 1500
2) (integer) 1000

开始测试模拟多个线程来操作

redis 客户端 1

  • money 账户 有 2000
  • outer 账户 有 500
  • money 账户 给 outer 账户 500 ,还未开始执行
127.0.0.1:6379> set money 2000
OK
127.0.0.1:6379> set outer 500
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> DECRBY money 500
QUEUED
127.0.0.1:6379(TX)> INCRBY outer 500
QUEUED

客户端 1 的事务操作还未开始执行,客户端 2 就进行了如下操作

127.0.0.1:6379> set money 10000
OK
127.0.0.1:6379> set money 10000
OK

此时执行客户端 1 的 exec 指令

127.0.0.1:6379(TX)> exec
(nil)
127.0.0.1:6379> get money
"10000"

发现客户端 1 执行 exec 的时候,是一个 nil ,说明变更失败,是因为 watch 监控到 money 有变动,因此事务执行失败

unwatch

发现事务执行失败了,需要使用命令 unwatch 解除监控

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 1000
QUEUED
127.0.0.1:6379(TX)> INCRBY outer 1000
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 9000
2) (integer) 1500

这就是 redis 实现乐观锁的操作,一般使用场景会放到秒杀系统里面进行应用

参考资料:

redis_doc

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是小魔童哪吒,欢迎点赞关注收藏,下次见~

相关实践学习
基于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
相关文章
|
24天前
|
NoSQL Redis 数据库
什么是Redis的事务?
Redis事务提供原子性和顺序性,确保命令按顺序执行且不被打断。核心概念包括原子性、顺序性、隔离性和持久性。关键指令有MULTI、EXEC、DISCARD和WATCH,用于事务的开始、执行、取消和监视。这保障了命令的完整性,防止并发操作导致的数据不一致。
12 2
|
1月前
|
缓存 监控 NoSQL
Redis 的监控指标
Redis 的监控指标
24 0
|
2月前
|
监控 NoSQL Redis
HeartBeat监控Redis状态
HeartBeat监控Redis状态
|
2月前
|
监控 NoSQL Redis
MetricBeat监控Redis
MetricBeat监控Redis
|
2月前
|
缓存 NoSQL 数据处理
Redis事务悄然而至:命令的背后故事
Redis事务悄然而至:命令的背后故事
27 0
|
24天前
|
NoSQL Redis
Redis事务:保证数据操作的一致性和可靠性
Redis事务:保证数据操作的一致性和可靠性
|
1月前
|
存储 NoSQL Java
【Redis】1、学习 Redis 的五大基本数据类型【String、Hash、List、Set、SortedSet】
【Redis】1、学习 Redis 的五大基本数据类型【String、Hash、List、Set、SortedSet】
54 0
|
2月前
|
消息中间件 NoSQL Kafka
Redis事务与异步方式
Redis事务与异步方式
35 0
|
2月前
|
存储 NoSQL 算法
学习 Redis 基础数据结构,不讲虚的。
职场中是这样使用 redis 的。
154 1
学习 Redis 基础数据结构,不讲虚的。
|
2月前
|
NoSQL Java API
分布式锁【数据库乐观锁实现的分布式锁、Zookeeper分布式锁原理、Redis实现的分布式锁】(三)-全面详解(学习总结---从入门到深化)
分布式锁【数据库乐观锁实现的分布式锁、Zookeeper分布式锁原理、Redis实现的分布式锁】(三)-全面详解(学习总结---从入门到深化)
298 0

热门文章

最新文章