IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> Redis中的事务 -> 正文阅读

[大数据]Redis中的事务

Redis中的事务本质是一组命令的集合。事务中的每条命令都会被序列化,执行过程中按顺序执行,不允许其他命令进行干扰。提炼一下即:(1)一次性(2)顺序性(3)排他性。

值得注意的是:Redis事务没有隔离级别的概念;此外,Redis单条命令是保证原子性的,但是事务不保证原子性。

Redis事务操作过程

  1. 开启事务(multi)
  2. 命令入队
  3. 执行事务(exec)

因此开启事务以后的所有命令,在加入队列时都没有被执行,而是直到提交时才会开始执行(exec),并一次性执行完毕。

127.0.0.1:6379> multi	# 开启事务
OK
127.0.0.1:6379(TX)> set k1 v1	# 将命令入队(此时并不执行,而是等exec一并执行)
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)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> keys *
QUEUED
127.0.0.1:6379(TX)> exec	# 事务执行
1) OK
2) OK
3) "v2"
4) OK
5) 1) "k2"
   2) "k3"
   3) "k1"

取消事务(discard

与exec相反,discard命令可以撤销事务中的所有命令,使其不执行。

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)> get k1
QUEUED
127.0.0.1:6379(TX)> discard
OK
127.0.0.1:6379> exec
(error) ERR EXEC without MULTI
127.0.0.1:6379> get k1
(nil)

可见上述代码中,set的k1和k2,由于使用了discard放弃了事务,因此所有的命令都没有得到执行。

事务错误

事务的错误分为两种:代码语法错误(编译时异常),代码逻辑错误(运行时异常)。

(1)编译时异常:事务中所有的命令都不执行

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)> this is an error command	# 这是一条代码语法错误
(error) ERR unknown command `this`, with args beginning with: `is`, `an`, `error`, `command`,
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1
(nil)

可见事务中一旦出现代码语法错误,则事务中所有的命令都不执行。

(2)运行时错误:该条命令错误执行,而其他命令正常执行(因此Redis事务不保证原子性

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)> incr k1
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
3) (error) ERR value is not an integer or out of range
4) "v1"
127.0.0.1:6379> get k2
"v2"

可见上述代码中,由于k1对应的值是字符串类型的v1,所以incr命令会出现运行时错误。但运行时错误只对这一条单独的命令有影响,而事务中其他的命令仍然可以正常执行。这说明了并不能保证Redis事务的原子性。

监控(可用作乐观锁的实现)

乐观锁:认为什么时候都不会出现问题,所以不会上锁。更新数据的时候去判断一下在此期间是否有其他线程修改过这个数据。首先要获取version,然后在更新的时候比较version。

使用 watch key 监控某个数据,相当于乐观锁加锁。

下面先来一个单线程正常的案例:

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> clear
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
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 20
QUEUED
127.0.0.1:6379(TX)> incrby out 20
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 80
2) (integer) 20

可见上述代码中,虽然对money进行了watch,但由于没有其他线程对money进行修改,所以该事务在更新money的时候,其当前版本号与期望版本号一致,所以可以修改成功。

===========================================================

下面模拟两个线程,另一个线程修改值的情况,此时使用watch起到了乐观锁的作用:

线程1:

127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 20
QUEUED
127.0.0.1:6379(TX)> incrby out 20
QUEUED
127.0.0.1:6379(TX)>		#执行到这里,事务并没有提交

此时线程2突然插队,改掉了money的值:

127.0.0.1:6379> incrby money 1000
(integer) 1080

此时回到线程1,执行事务:

127.0.0.1:6379(TX)> exec
(nil)
127.0.0.1:6379> get money
"1080"
127.0.0.1:6379> get out
"20"

此时由于在exec执行之前,线程2把money的值改掉了,由于money在线程1中受到了watch,因此此时事务执行失败。此时再去得到money和out的值,money为线程2修改后的,而out为初始的(这里为20是因为上面一个程序加了20,并不是这个事务操作的)。

如果想要通过线程1对money进行修改,要用unwatch解锁,来获取最新值,然后再加锁进行事务操作。

127.0.0.1:6379> unwatch
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> decrby money 20
QUEUED
127.0.0.1:6379(TX)> incrby out 20
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 1060
2) (integer) 40

值得注意的是,每次提交执行exec后都会自动释放锁,不管是否成功。

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-11-27 09:57:56  更:2021-11-27 10:00:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:42:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码