【Redis系列笔记】Redis事务

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
云原生多模数据库 Lindorm,多引擎 多规格 0-4节点
简介: Redis事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。

1. 概念

Redis事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。

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

Reids中,单条命令式原子性执行的,但不保证原子性,且没有回滚

1.1. 传统事务和Redis事务的区别

特性名称

传统事务

Redis事务

原子性

事务是不可分割的最小操作单元,要么全部成功,要么全部失败

不保证原子性:事务中如果有一条命令执行失败,其他的命令仍然执行,不保证回滚

一致性

事务完成时,必须使所有的数据都保持一致状态

隔离性

数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行

没有隔离级别的概念:队列中的命令没有提交之前都不会被执行。事务中的所有命令都会被序列化,按顺序的执行,事务在执行过程中不会被其他客户端发来的命令所打断。

持久性

事务一旦提交或回滚,它对数据库中的数据的改变就是永久的

事务提交之后,会根据RDB或者AOF进行持久化到磁盘中

1.2. 特点

优点:

  • 一次性按顺序执行多个Redis命令,不受其他客户端命令请求影响;
  • 事务中的命令要么都执行(命令间执行失败互相不影响),要么都不执行(比如中间有命令语法错误);

缺点:

  • 事务执行时,不能保证原子性;
  • 命令入队每次都需要和服务器进行交互,增加带宽;

注意:

  • 当事务中命令语法使用错误时,最终会导致事务执行不成功,即事务内所有命令都不执行;
  • 当事务中命令知识逻辑错误,就比如给字符串做加减乘除操作时,只能在执行过程中发现错误,这种事务执行中失败的命令不影响其他命令的执行。

2. 事务命令

命令

解释

作用

multi

开启事务

设定事务的开启位置,此指令执行后,后续的所有指令均加入到事务中

exec

执行事务

设定事务的结束位置,同时执行事务,与multi配合使用。

discard

取消事务

放弃执行事务块中的所有命令。

watch

监听

监视一个或多个键,如果在事务执行之前这些键被其他命令所改动,那么事务将会被打断。

unwatch

取消监听

取消所有由 WATCH 命令监视的键。如果不想继续监视某些键,可以使用 UNWATCH 命令来取消监视。

注意:

  1. 加入事务的命令暂时进入到任务队列中,并没有立即执行,只有执行exec命令才开始执行。
  2. 在事务执行过程中,其他客户端提交的命令请求不会插入到事务执行命令序列中,这保证了事务的隔离性。
  3. 事务提供了批量操作缓存的功能,即在发送 EXEC 命令前,所有操作都会被放入队列缓存。

3. 事务使用

3.1. 正常执行

192.168.xxx.21:6379> multi
OK
192.168.xxx.21:6379> set aa AA
QUEUED
192.168.xxx.21:6379> set bb BB
QUEUED
192.168.xxx.21:6379> set cc CC
QUEUED
192.168.xxx.21:6379> set dd DD
QUEUED
192.168.xxx.21:6379> exec
1) OK
2) OK
3) OK
4) OK
192.168.xxx.21:6379> get aa
"AA"
  1. 通过执行multi命令开始一个事务块。然后,依次执行了四个set命令,每个set命令执行后返回的结果为"QUEUED",表示该命令已被加入到事务队列中等待执行。
  2. 通过执行exec命令来提交事务,一次性执行事务队列中的所有命令。执行结果为每个命令的返回值,即"OK"。
  3. 通过执行get aa命令获取键"aa"的值,返回结果为"AA"。

3.2. 取消事务

192.168.xxx.21:6379> multi
OK
192.168.xxx.21:6379> set aa 11
QUEUED
192.168.xxx.21:6379> set ee EE
QUEUED
192.168.xxx.21:6379> discard
OK
192.168.xxx.21:6379> get aa
"AA"
192.168.xxx.21:6379> get ee
(nil)
192.168.xxx.21:6379>
  1. 通过执行multi命令开始一个事务块。然后,依次执行了两个set命令,每个set命令执行后返回的结果为"QUEUED",表示该命令已被加入到事务队列中等待执行。
  2. 通过执行discard命令来取消事务,放弃执行事务块内的所有命令。执行结果为"OK"。
  3. 通过执行get aa命令获取键"aa"的值,返回结果为"AA"。而执行get ee命令获取键"ee"的值时,由于之前已经取消了事务,所以返回结果为"(nil)",表示该键不存在。

3.3. 事务队列中存在命令错误

192.168.xxx.21:6379> multi
OK
192.168.xxx.21:6379> set aa 22
QUEUED
192.168.xxx.21:6379> set bb 33
QUEUED
192.168.xxx.21:6379> setq cc 44
(error) ERR unknown command 'setq'
192.168.xxx.21:6379> set ff FF
QUEUED
192.168.xxx.21:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
192.168.xxx.21:6379> get ff
(nil)
192.168.xxx.21:6379> get bb
"BB"
192.168.xxx.21:6379>
  1. 通过执行multi命令开始一个事务块。然后,依次执行了三个set命令,每个set命令执行后返回的结果为"QUEUED",表示该命令已被加入到事务队列中等待执行。然而,在执行第三个set命令时,出现了错误。因为Redis中并没有名为"setq"的命令,所以返回结果为"(error) ERR unknown command ‘setq’"。
  2. 通过执行exec命令来提交事务,一次性执行事务队列中的所有命令。由于之前已经出现了错误,导致事务被中断,所以执行结果为"(error) EXECABORT Transaction discarded because of previous errors."。
  3. 通过执行get ff命令获取键"ff"的值时,由于事务被中断,所以返回结果为"(nil)“,表示该键不存在。而执行get bb命令获取键"bb"的值时,由于事务被中断,所以返回结果为"BB”。

总结:如果在事务队列中存在命令性错误(类似于java编译性错误),则执行EXEC命令时,所有命令都不会执行

3.4. 事务队列中存在语法错误

192.168.xxx.21:6379> multi
OK
192.168.xxx.21:6379> incr aa
QUEUED
192.168.xxx.21:6379> set ff FF
QUEUED
192.168.xxx.21:6379> set bb 22
QUEUED
192.168.xxx.21:6379> exec
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
192.168.xxx.21:6379> get bb
"22"
192.168.xxx.21:6379> get ff
"FF"
192.168.xxx.21:6379>

过程同上,但incr aa时由于aa的值为AA,字符串无法加1

总结:如果在事务队列中存在语法性错误(类似于java的1/0的运行时异常),则执行EXEC命令时,其他正确命令会被执行,错误命令抛出异常。

3.5. watch监听

192.168.xxx.21:6379> watch aa
OK
192.168.xxx.21:6379> set aa Aa
OK
192.168.xxx.21:6379> get aa
"Aa"
192.168.xxx.21:6379> multi
OK
192.168.xxx.21:6379> set aa 11
QUEUED
192.168.xxx.21:6379> exec
(nil)
192.168.xxx.21:6379> get aa
"Aa"
192.168.xxx.21:6379>

watch 命令可以监听一个或多个键,一旦有其中一个键被修改(被删除),后面的事务就不会执行了。

当watch监听多个键时,执行某事务希望取消对其中某个键的监听,可以在事务执行前或者执行后使用unwatch声明取消监听。

192.168.xxx.21:6379> get bb
"BBB"
192.168.xxx.21:6379> watch bb
OK
192.168.xxx.21:6379> multi
OK
192.168.xxx.21:6379> unwatch
QUEUED
192.168.xxx.21:6379> set bb 222
QUEUED
192.168.xxx.21:6379> exec
1) OK
2) OK
192.168.xxx.21:6379> get bb
"222"
192.168.xxx.21:6379>
相关实践学习
基于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
目录
相关文章
|
2月前
|
缓存 NoSQL Redis
Redis 事务
10月更文挑战第18天
26 1
|
4月前
|
负载均衡 NoSQL 算法
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
这篇文章是关于Java面试中Redis相关问题的笔记,包括Redis事务实现、集群方案、主从复制原理、CAP和BASE理论以及负载均衡算法和类型。
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
|
2月前
|
SQL 分布式计算 NoSQL
大数据-42 Redis 功能扩展 发布/订阅模式 事务相关的内容 Redis弱事务
大数据-42 Redis 功能扩展 发布/订阅模式 事务相关的内容 Redis弱事务
25 2
|
2月前
|
NoSQL 关系型数据库 MySQL
Redis 事务特性、原理、具体命令操作全方位诠释 —— 零基础可学习
本文全面阐述了Redis事务的特性、原理、具体命令操作,指出Redis事务具有原子性但不保证一致性、持久性和隔离性,并解释了Redis事务的适用场景和WATCH命令的乐观锁机制。
281 0
Redis 事务特性、原理、具体命令操作全方位诠释 —— 零基础可学习
|
7月前
|
NoSQL Java 关系型数据库
【Redis系列笔记】分布式锁
分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁,只要大家使用的是同一把锁,那么我们就能锁住线程,不让线程进行,让程序串行执行,这就是分布式锁的核心思路
662 2
|
4月前
|
NoSQL 关系型数据库 Redis
Redis6入门到实战------ 九、10. Redis_事务_锁机制_秒杀
这篇文章深入探讨了Redis事务的概念、命令使用、错误处理机制以及乐观锁和悲观锁的应用,并通过WATCH/UNWATCH命令展示了事务中的锁机制。
Redis6入门到实战------ 九、10. Redis_事务_锁机制_秒杀
|
3月前
|
监控 NoSQL 关系型数据库
9)Redis 居然也有事务
9)Redis 居然也有事务
34 0
|
5月前
|
监控 NoSQL Redis
Redis事务和Redis管道
Redis事务和Redis管道
62 0
|
6月前
|
存储 NoSQL Java
Redis系列学习文章分享---第八篇(Redis快速入门之达人探店--发布探店笔记 + 查看探店笔记 + 点赞功能 + 点赞排行榜)
Redis系列学习文章分享---第八篇(Redis快速入门之达人探店--发布探店笔记 + 查看探店笔记 + 点赞功能 + 点赞排行榜)
32 0
|
7月前
|
NoSQL 关系型数据库 MySQL
Redis(事务)
Redis(事务)
54 2

相关产品

  • 云数据库 Tair(兼容 Redis)