十二、Redis进阶-事物参考记录

作者: 温新

分类: 【Redis】

阅读: 1916

时间: 2020-09-02 13:11:58

事务介绍

Redis中的事务(transaction)是一组命令的集合。事物与命令一样都是Redis的最小 执行单位,一个事务中的命令要么全部执行,要么全部不执行。

举个栗了,银行转账,A给B汇款,首先,系统从A的账号中将钱划走,然后向B的账户增加相应的金额。这个过程必须是同一个事务,要么全部执行,要么全部不执行。

事务执行流程

Redis事务可以一次执行多个命令,且有如下保证:

1)批量操作在发送exec命令前被放入队列缓存

2)收到exec命令后进入事务执行,事务中任意命令执行失败,其余命令依旧被执行

3)事务执行过程中,其他客户端提交的命令请求不会插入到事务执行命令序列中

一个事务从开始到执行经历三个阶段

1)开始事务 2)命令入列 3)执行事务

事务命令

multi开启一个事务

exec执行一个事务

watch监听一个或多个key

unwatch取消wacth命令对所有key的监听

discard取消事务

Redis事务实际案例

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 1)开启事务</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379>  multi</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 2)执行命令</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> sadd user:1:following <span style="box-sizing: border-box;color: rgb(255, 83, 112)">2</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">QUEUED</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> sadd user:2:following <span style="box-sizing: border-box;color: rgb(255, 83, 112)">1</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">QUEUED</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 3)exec执行事务</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> exec</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">1</span>) (integer) <span style="box-sizing: border-box;color: rgb(255, 83, 112)">1</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">2</span>) (integer) <span style="box-sizing: border-box;color: rgb(255, 83, 112)">1</span></span>

解释

1)multi命令告诉Redis开启事务,下面的命令都是同一个事务,你先不要执行,把它们存起来。

Redis回答“OK”。

2)接下来是我们要操作的命令了,执行两个sadd命令,Redis果然遵守的承诺,回答QUEUED,表示命令已经进入等待执行的事务队列中。

3)命令完毕后,使用EXEC命令告诉Redis我的命令完毕了,开始执行事务。Redis收到执行事务的命令之后,按照Redis命令发送的顺序依次执行。

Redis保证一个事务中的命令要么全部执行,要么全部不执行。如果在exec前客户端断线了,Redis则清空事务队列,事务中所有命令都不执行。

事务错误处理

语法错误,指命令不存在或着命令参数的个数不对,如下案例

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> multi</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> name ziruchu</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">QUEUED</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> name</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">(error) ERR wrong number of arguments <span style="box-sizing: border-box;color: rgb(199, 146, 234)">for</span> <span style="box-sizing: border-box;color: rgb(195, 232, 141)">'set'</span> command</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> exec</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">(error) EXECABORT Transaction discarded because of previous errors.</span>

执行3个命令,一个正确,加入队列,其余存在语法错误。只要一个有语法错误,执行exec将直接返回错误

运行错误指命令执行时出现错误。

如用哈希类型操作集合类型的键,这种错误在被实际执行前,Redis无法发现,因此,事务中这样的命令会被Redis接受并执行。

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> multi</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> name ziruchu</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">QUEUED</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> sadd name php</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">QUEUED</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> name mysql</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">QUEUED</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> exec</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">1</span>) OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">2</span>) (error) WRONGTYPE Operation against a key holding the wrong kind of value</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">3</span>) OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(255, 203, 107)">get</span> name</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(195, 232, 141)">"mysql"</span></span>

实际操作可见,sadd name php出错,但set name mysql依旧被执行,Redis事务没有回滚功能,因此一定要小心。

watch监听一个或多个key

watch命令可以监听一个或多个键,一旦其中有一个键被修改或删除,之后的事务将不执行。监听一直持续到exec命令。

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> name php</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> watch name</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> name ziruchu</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> multi</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> name mysql</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">QUEUED</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> exec</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">(nil)</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(255, 203, 107)">get</span> name</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(195, 232, 141)">"ziruchu"</span></span>

上述案例中,首先设置一个name,其次监听name,其三再监听这个name,其四开启事务,其五设置name,其六执行事务。结果name没有被事务中的命令修改。

我是夕阳何处寻,期待和优秀的你一起同行!

小白

2020年09月02日

请登录后再评论