前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >七天玩转Redis | Day4、Redis事务操作

七天玩转Redis | Day4、Redis事务操作

作者头像
灰小猿
发布2022-05-05 21:07:12
2080
发布2022-05-05 21:07:12
举报
文章被收录于专栏:灰小猿技术社区

博主简介👨🏼‍⚕️:国内某一线互联网公司Java工程师👨🏼‍💻,业余自媒体创作者💻,CSDN博客专家🏆,Java领域优质创作者📕,华为云享专家🥇,华为HDZ核心成员👨‍💼,曾发表并出版ISEAE信息科学国际论文,全网累计发表技术博客60余万字📒,公众号【码猿编程日记】作者,坚信每一次敲动键盘都能让生活变得更智能,世界变得更有趣!

课前答疑:很多小伙伴问我零基础或者根本没有使用过Redis,可以学习嘛?当然是可以的!充分考虑到小伙伴们的学习程度有所不同,所以本次课程的所有操作都是在Windows环境下进行的,不会依赖太多的环境配置,且上手容易。已经学习过Redis的小伙伴们同样可以再学习一遍,温故而知新,还能拿CSDN定制周边!何乐而不为呢😀

今日学习内容

今天这一篇文章主要来和大家分享一下在Redis中的事务操作以及如何通过Redis来实现乐观锁操作。

首先什么是事务?事务一般都是用于表示对数据库的一系列操作的集合,简单来说就是把多条语句放在一起执行就叫事务。它的特点是要么全执行,要么全不执行。在MySQL中事务有四大特性,分别是:原子性、一致性、隔离性、持久性,简称是ACID特性,

但是在Redis中的事务和MySQL中的事务稍有不同,在Redis中的事务本质上其实是一组命令操作的集合,在事务执行的过程中,这些命令会被序列化,按照顺序依次执行。所以Redis中的事务具有的特点是:一次性、顺序性、排他性。

  • 一次性:指的是Redis中的事务只执行一次,在该事务执行结束之后,这条事务的生命周期就结束了,再次执行事务时需要重新开启事务。
  • 顺序性:指Redis的事务中的所有命令,都是按照先后顺序依次执行的。
  • 排他性:指事务在对某一个数据进行操作的同时,其他事务或其他命令不能对这个数据进行操作。

Redis中的事务是没有隔离性的,因此也更不具备隔离级别这一说法,并且Redis的事务并不是直接执行的,而是需要经过命令提交时候才能执行,Redis事务的执行流程图如下:

同时Redis的单条命令具有原子性(也就是要么成功,要么失败),但是对于存在多条命令的Redis事务来说,不具备原子性,也就是说如果事务中有其他命令执行失败了,其他命令还会执行下去。

(1)正常执行事务

我们先来模拟一个事务正常执行的过程,

第一步,开启事务

在事务执行之前,我们需要先使用MULTI命令来开启事务,

开启事务命令 MULTI

第二步,命令入队

开启事务时候就需要向该事务中加入命令,将命令入队,这一步你可以任意写入你想要执行的命令。注意:在将命令添加到队列之后,命令并不会立即执行,而是返回一个QUEUED,表示入队成功!

第三步,提交命令

在我们将所有的命令都入队之后,就可以提交执行这个事务了,提交事务的命令是:

提交事务 EXEC

事务提交之后就会按照我们入队的命令的顺序来执行命令,在命令执行完毕之后就会将这个事务自动关闭。并且返回事务中所有命令的执行结果!

代码语言:javascript
复制
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET k1 v1
QUEUED
127.0.0.1:6379> SET k2 v2
QUEUED
127.0.0.1:6379> GET k1
QUEUED
127.0.0.1:6379> SET k3 v3
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
3) "v1"
4) OK

(2)取消事务执行

如果在我们的事务没有提交之前,你想要取消执行这个事务,那么可以使用DISCARD命令,这样这个事务就会被自动取消,其中入队的命令也不会被执行,在下一次执行事务时还需要重新再开启事务!

取消事务 DISCARD

如我们取消正在向队列中加入命令的事务:

代码语言:javascript
复制
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET k4 v4
QUEUED
127.0.0.1:6379> SET k5 v5
QUEUED
127.0.0.1:6379> DISCARD
OK

(3)事务编译时异常

在事务执行或者命令入队的时候也是会发生错误的,和在Java代码中一样,如果我们的命令在书写上就存在明显代码错误,那么就会发生编译时异常,这个时候会有错误提示,但是事务仍能提交,但是提交之后,整个事务队列中的命令都不会执行,

比如下面的例子,我们随便写入一个不存在的命令并提交执行,执行完之后去查看我们的数据是否添加成功!

代码语言:javascript
复制
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET k5 v5
QUEUED
127.0.0.1:6379> SETGET k6 v6    #输入错误命令
(error) ERR unknown command `SETGET`, with args beginning with: `K6`, `V6`,
127.0.0.1:6379> GET k5
QUEUED
127.0.0.1:6379> EXEC    #事务执行报错
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> GET k6
(nil)

(4)运行时异常

运行时异常与编译时异常不同,运行时一样在编写代码时不会提示,一般情况下是我们的代码编写正确,但是存在逻辑问题,比如1/0这样的。

在Redis中如果事务中的命令存在运行时异常,那么在提交事务之后,不存在异常的命令同样会被执行,异常的命令会单独执行失败!

如下,我们在事务中输入一个运行时会发生错误的命令INCR k9,给k9加一,但是k9并不存在,所以在提交事务之后该命令会执行失败,但是其他没有异常的命令可以执行成功!

代码语言:javascript
复制
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET k7 v7
QUEUED
127.0.0.1:6379> INCR k9    #该命令运行时会报错,因为不存在k9
QUEUED
127.0.0.1:6379> GET k7
QUEUED
127.0.0.1:6379> SET k8 v8
QUEUED
127.0.0.1:6379> EXEC    #事务可以正常提交,但是异常的命令单独报错
1) OK
2) (error) ERR value is not an integer or out of range
3) "v7"
4) OK
127.0.0.1:6379> GET k8    #可以正常获取到k8的值
"v8"

(5)Redis乐观锁实现

Redis中其实也是有锁的机制的,而且锁可以分为乐观锁和悲观锁,

  • 悲观锁:认为什么时候都可能出错,所以在任何时候都会加锁
  • 乐观锁:认为什么时候都不会出错,所以什么时候都不会加锁,在更新数据的时候只需要去判断,在此期间是否有人修改过这个数据即可!

所以如果想要实现乐观锁,我们需要使用一个命令去监控我们要操作的字段,在Redis中这个命令是:

WATCH key

  • key要监控的字段的索引

如果想要实现锁,那么一定是要伴随着事务进行的。

我们以超市消费作为一个例子来实现Redis的乐观锁和监控,先定义一个money字段表示我们的钱,定义一个outMoney字段表示花出去的钱,我们现在要开启一个事务执行下面这样一个任务:“money'花出去10元,则outMoney增加10元”,在开启事务之前先使用WATCH命令去监控money字段。

代码语言:javascript
复制
127.0.0.1:6379> SET money 100    #设置money为100
OK    
127.0.0.1:6379> SET outMoney 0    #设置outMoney为100
OK
127.0.0.1:6379> WATCH money        #监控money
OK
127.0.0.1:6379> MULTI    #开启事务
OK
127.0.0.1:6379> DECRBY money 10    #money减10
QUEUED
127.0.0.1:6379> INCRBY outMoney 10    #outMoney加10
QUEUED
127.0.0.1:6379> EXEC    #提交事务,执行成功
1) (integer) 90
2) (integer) 10

上面是一个正确的操作,没有问题,

但是如果我们现在重复刚才的操作(正常情况下money应该变成80),但是并不急着提交事务,而且开启一个新的Redis客户端,在其中对我们的money加10,之后再提交上一个上一个事务,就会提示我们的money已经被修改,这个时候事务一定是执行失败的! 如下:

1、首先去监控money,并开始一个事务,将命令入队,但是不去提交,

代码语言:javascript
复制
127.0.0.1:6379> WATCH money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRBY money 10
QUEUED
127.0.0.1:6379> INCRBY outMoney 10
QUEUED

2、打开一个新的Redis客户端,修改money的值

代码语言:javascript
复制
127.0.0.1:6379> INCRBY money 10
(integer) 100

3、返回第一个Redis客户端,提交修改,并查询money的值,显示money值为100

代码语言:javascript
复制
127.0.0.1:6379> WATCH money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> DECRBY money 10
QUEUED
127.0.0.1:6379> INCRBY outMoney 10
QUEUED
127.0.0.1:6379> EXEC
(nil)
127.0.0.1:6379> GET money
"100"

 这就说明,在给字段添加监控的情况下通过事务去操作字段,如果在未提交时,有新的命令修改了字段值,那么事务一定会提交失败,但是在未监控的情况下,事务仍能提交成功!这就是Redis的乐观锁实现! 所以在实现乐观锁时,开启事务之前,一定要先给字段增加监控! 所以:Redis是可以实现乐观锁的!(面试的时候可是经常会问的!) 另外注意:Redis在每次事务提交之后,无论事务执行成功与否,该事务都会关闭,监控也会自动取消,在下次执行事务时都需要重新开启!

今日总结

今天主要和大家讲解了在Redis中的事务操作,它是保护数据安全的一大举措,而且在开发中Redis的事务使用也是非常广泛的,所以Redis的事务和乐观锁的实现,小伙伴们一定要记住哈,而且这也是面试的高频!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-01-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 今日学习内容
  • (1)正常执行事务
  • (2)取消事务执行
  • (3)事务编译时异常
  • (4)运行时异常
  • (5)Redis乐观锁实现
  • 今日总结
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档