ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

【Redis】事务和锁

2020-07-05 18:01:35  阅读:284  来源: 互联网

标签:事务 127.0 0.1 age Redis 6379 QUEUED


纸上得来终觉浅,绝知此事要躬行。

什么是事务

事务可以一次执行多个命令,本质是一组命令的集合, 并且带有以下两个重要的保证:

  • 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
  • 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。

为什么要事务

首先我们先来看一个案例:

session-1 session-2
127.0.0.1:6379> set money 1000
OK
127.0.0.1:6379> set money 1
OK
127.0.0.1:6379> get money
"1"
127.0.0.1:6379> get money
"1"

上面相当于两个客户端同时进行,session-1为客户端1,session-2为客户端2。客户端1先set money 1000,紧接着客户端2执行set money 1,当客户端1通过get money查看的时候最终的值变成了1,也就是说客户端1在执行的过程中被客户端2插队了,有没有办法保证一个客户端在执行过程中整个操作是一个整体,有,就是下面需要了解的事务以及事务相关的操作命令。

事务的操作

MULTI

  • 用于开启一个事务,它总是返回 OK 。 MULTI 执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中。 所有传入的命令都会返回一个内容为 QUEUED 的状态回复(status reply), 这些被入队的命令将在 EXEC 命令被调用时执行。
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set age 22
QUEUED
127.0.0.1:6379> INCR age
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> 

EXEC

  • 命令被调用时, 所有队列中的命令才会被执行。回复是一个数组, 数组中的每个元素都是执行事务中的命令所产生的回复。 其中, 回复元素的先后顺序和命令发送的先后顺序一致。
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set age 22
QUEUED
127.0.0.1:6379> INCR age
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) (integer) 23
3) "23"
127.0.0.1:6379>

DISCARD

  • 命令被调用时,客户端可以清空事务队列, 并放弃执行事务。之后不能在提交。
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set age 22
QUEUED
127.0.0.1:6379> INCR age
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> EXEC
(error) ERR EXEC without MULTI
127.0.0.1:6379> 

事务工作流程

事务工作流程

事务中的错误

使用事务时可能会遇上以下两种错误:

  • 事务在执行 EXEC 之前,入队的命令可能会出错。比如说,命令可能会产生语法错误(参数数量错误,参数名错误,等等),或者其他更严重的错误。
127.0.0.1:6379> set name ydongy
QUEUED
127.0.0.1:6379> aaa name ydongy2
(error) ERR unknown command `aaa`, with args beginning with: `name`, `ydongy2`, 
127.0.0.1:6379> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> 

我们发现,当事务中出现语法错误,最后exec提示事务不存在,也就是说在事务中执行语法错误,整体事务中所有命令均不会执行。包括那些语法正确的命令

  • 命令可能在 EXEC 调用之后失败。举个例子,事务中的命令可能处理了错误类型的键,比如将列表命令用在了字符串键上面,诸如此类。
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set name ydongy
QUEUED
127.0.0.1:6379> get name
QUEUED
127.0.0.1:6379> set age 22
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> lpush name 1 2 3
QUEUED
127.0.0.1:6379> get name
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) "ydongy"
3) OK
4) "22"
5) (error) WRONGTYPE Operation against a key holding the wrong kind of value
6) "ydongy"
127.0.0.1:6379> 

上面的案例有一步错误操作,就是把name当成列表进行追加数据,语法本身没有错,但是在最后执行的时候那一条指令并没有执行,但是整个事务中正确的指令都执行了。需要注意已经执行完毕的命令对应的数据不会自动回滚,即 Redis 不支持回滚,需要程序员自己在代码中实现回滚。

业务场景:

业务场景

为了解决这种并发操作带来的问题,Redis 的 WATCH 命令可以为事务提供 check-and-set (CAS)行为,即:乐观锁。被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消。

session-1 session-2
127.0.0.1:6379> set age 22
OK
127.0.0.1:6379> get age
"22"
127.0.0.1:6379> WATCH age
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> INCR age
QUEUED
127.0.0.1:6379> DECR age
(integer) 21
127.0.0.1:6379> EXEC
(nil)
127.0.0.1:6379> get age
"21"
127.0.0.1:6379> get age
"21"

通过EXEC 返回nil来表示事务已经失败。当 EXEC 被调用时,不管事务是否成功执行,对所有键的监视都会被取消。另外,当客户端断开连接时,该客户端对键的监视也会被取消。如果需要WATCH 对多个键进行监视,可以使用无参数的 UNWATCH 命令手动取消对所有键的监视。

标签:事务,127.0,0.1,age,Redis,6379,QUEUED
来源: https://www.cnblogs.com/ydongy/p/13229574.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有