Redis 事务(8)

Stella981
• 阅读 379

为什么要用事务

Redis的单个命令是原子性的(比如get set mget mset),如果涉及到多个命令的时候,需要把多个命令作为一个不可分割的处理序列,就需要用到事务。

例如我们之前说的用setnx实现分布式锁,我们先set,然后设置对key设置expire,防止del发生异常的时候锁不会被释放,业务处理完了以后再del,这三个动作我们就希望它们作为一组命令执行。

Redis的事务有两个特点:

  1. 按进入队列的顺序执行。
  2. 不会受到其他客户端的请求的影响。
Redis的事务涉及到四个命令:

命令

说明

multi

开启事务

exec

执行事务

discard

取消事务

watch

监视

事务用法

案例:张三(zhangsan)和李四(lisi)各有100元,张三需向李四转账50元。张三账户余额减少50元,李四的账户余额增加50元。

127.0.0.1:6379> set zhangsan 100
OK
127.0.0.1:6379> set lisi 100
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby zhangsan 50
QUEUED
127.0.0.1:6379> incrby lisi 50
QUEUED
127.0.0.1:6379> exec
1) (integer) 50
2) (integer) 150
127.0.0.1:6379> get zhangsan
"50"
127.0.0.1:6379> get lisi
"150"

通过multi的命令开启事务。事务不能嵌套,多个multi命令效果一样。

multi执行后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当exec命令被调用时,所有队列中的命令才会被执行。

通过exec的命令执行事务。如果没有执行exec,所有的命令都不会被执行。

如果中途不想执行事务了,怎么办?

可以调用discard可以清空事务队列,放弃执行。

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set s1 1
QUEUED
127.0.0.1:6379> set s2 2
QUEUED
127.0.0.1:6379> set s3 3
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get s1
(error) WRONGTYPE Operation against a key holding the wrong kind of value

开通两个客户端

####------>>>>>第一个客户端执行命令
127.0.0.1:6379> set zhangsan 1000
OK
127.0.0.1:6379> get zhangsan
"1000"
127.0.0.1:6379> watch zhangsan
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby zhangsan 100
QUEUED

####------>>>>>第二个客户端执行命令
127.0.0.1:6379> decrby zhangsan 100
(integer) 900

####------>>>>>第一个客户端执行命令
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get zhangsan
"900"

事务可能遇到的问题

我们把事务执行遇到的问题分成两种,一种是在执行exec之前发生错误,一种是在执行exec之后发生错误。

在执行exec之前发生错误

比如:入队的命令存在语法错误,包括参数数量,参数名等等(编译器错误)。

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set list 111
QUEUED
127.0.0.1:6379> hset list 222
(error) ERR wrong number of arguments for 'hset' command
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.

在这种情况下事务会被拒绝执行,也就是队列中所有的命令都不会得到执行。

在执行exec之后发生错误

比如,类型错误,比如对String使用了Hash的命令,这是一种运行时错误。

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set s1 1
QUEUED
127.0.0.1:6379> hset s1 a b
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> get s1
"1"

最后我们发现setk11的命令是成功的,也就是在这种发生了运行时异常的情况下,只有错误的命令没有被执行,但是其他命令没有受到影响。

这个显然不符合我们对原子性的定义,也就是我们没办法用Redis的这种事务机制来实现原子性,保证数据的一致。

为什么在一个事务中存在错误,Redis不回滚?

这种方式也有其合理之处:只有当被调用的Redis命令有语法错误时,这条命令才会执行失败(在将这个命令放入事务队列期间,Redis能够发现此类问题),或者对某个键执行不符合其数据类型的操作:实际上,这就意味着只有程序错误才会导致Redis命令执行失败,这种错误很有可能在程序开发期间发现,一般很少在生产环境发现。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
佛系码 佛系码
3年前
Redis实现分布式锁
一、redis分布式锁的简易实现用redis实现分布式锁是一个老生常谈的问题了。因为redis单条命令执行的原子性和高性能,当多个客户端执行setnx(相同key)时,最多只有一个获得成功。因此在对可用性要求不是特别高的场景下,redis分布式锁方案不失为一个性价比高的实现。1.多个客户端执行setnxlock
Stella981 Stella981
2年前
Nginx + lua +[memcached,redis]
精品案例1、Nginxluamemcached,redis实现网站灰度发布2、分库分表/基于Leaf组件实现的全球唯一ID(非UUID)3、Redis独立数据监控,实现订单超时操作/MQ死信操作SelectPollEpollReactor模型4、分布式任务调试Quartz应用
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
京东云开发者 京东云开发者
8个月前
redis分布式锁,setnx+lua脚本的java实现 | 京东物流技术团队
本文是基于redis缓存实现分布式锁,其中使用了setnx命令加锁,expire命令设置过期时间并lua脚本保证事务一致性。Java实现部分基于JIMDB提供的接口
京东云开发者 京东云开发者
5个月前
线上SQL超时场景分析-MySQL超时之间隙锁 | 京东物流技术团队
前言之前遇到过一个由MySQL间隙锁引发线上sql执行超时的场景,记录一下。背景说明分布式事务消息表:业务上使用消息表的方式,依赖本地事务,实现了一套分布式事务方案消息表名:mqmessages数据量:3000多万索引:createtime和statuss
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这