MySQL和Redis事务的区别和用法

发布时间:2020-05-25 15:06:44 作者:三月
来源:PHP中文网 阅读:210

本篇文章给大家主要讲的是关于MySQLRedis事务的区别和用法的内容,感兴趣的话就一起来看看这篇文章吧,相信看完MySQL和Redis事务的区别和用法对大家多少有点参考价值吧。                                                          

Redis

[1] Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证:

一个事务从开始到执行会经历以下三个阶段:

单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。

事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。

操作错误

看着有点儿绕口,那就实际执行一下 看一下结果。

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set tr_1 233
QUEUED
127.0.0.1:6379> lpush tr_1 666
QUEUED
127.0.0.1:6379> set tr_2 888
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK

在上面的事务中,设置了一个 key 为 tr_1 的字符串数据,然后又通过 lpush 来添加元素,这很明显是错误的操作方式,当我们提交事务候出现了一个操作错误,这时候我们来看看 tr_1 的值是什么。

127.0.0.1:6379> get tr_1
"233"

通过 get 命令来的tr_1 内容还是 233 ,并没有变,那再看一下其他的。

127.0.0.1:6379> keys *
1) "tr_2"
2) "tr_1"
127.0.0.1:6379> get tr_2
"888"
127.0.0.1:6379>

这里可以看到 tr_2 存在,并打印了值,这时候我们发现,即使出现了操作错误 ,但是错误并没有致使执行停止,错误之后的语句也执行了并成功执行,似乎符合上面提到的 中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。

语法错误

NO~,这时候还有另外一种情况 语法错误

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set tr_1 233
QUEUED
127.0.0.1:6379> lpush tr_1 666
QUEUED
127.0.0.1:6379> set
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> set 233
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> set tr_2 888
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> keys *
(empty list or set)

当我们执行到 set时没有给任何参数,第二次执行时故意少给了一个参数。可以看到报了 语法错误,最后提交事务,也告诉了我们事务因为错误被丢失了,接着用 keys *检索发现确实如此。

文档释义

这里可以官方文档中提到的

Errors inside a transaction

// 在执行过程中 可能会遇到两种错误命令错误。

During a transaction it is possible to encounter two kind of command errors:

// 1.命令无法进入队列 ,比如 :参数数量错误,命令名错误...,或者某些关键错误 如内存不足

// 2. 对键进行错误的操作 如上面的 对字符串使用 lpush

// 客户端检查键入的命令,大多数时候会在调用 exec 前发现第一类错误,如果命令执行返回来 QUEUED 则表示命令正常进入队列,否则错误,大多数情况下客户端会终止放弃这个事务。

Clients used to sense the first kind of errors, happening before the EXEC call, by checking the return value of the queued command: if the command replies with QUEUED it was queued correctly, otherwise Redis returns an error. If there is an error while queueing a command, most clients will abort the transaction discarding it.

关于 Redis 暂时看到这里 接下来看到 MySQL

MySQL

众所周知,MySQL 只有 InnoDB 引擎支持 事务,在启用 MySQL 事务之前需要先停掉自动提交

测试表结构 user
类型注释
idint(11) 自动增量主键ID
moneyint(11) [0]金钱
titlevarchar(500) NULL称呼

在这里来模拟一个转账的操作:A给B转100元。

步骤解析 A+100 元,B -100元,即两步虽然很简单,简单走一下流程。

MySQL和Redis事务的区别和用法

可以看到,没有问题,那么我们从中人为的制造一些问题呢?

操作错误



类型注释
idint(11) 自动增量
moneyint(11) unsigned [0]
titlevarchar(500) NULL

这里我们把 money 字段变成了无符号,即不能小于 0,并且,调整数据库中的数据如下。

`SELECT * FROM `user` LIMIT 50` (0.000 秒)
修改idmoneytitle
编辑110000A
编辑20B

接着执行下面的 SQL

select version();
SET AUTOCOMMIT=0;
begin;
select * from user where title in ('A','B') for update;
update user set  money = money + 1000 where title = 'A';
update user set money = money - 1000 where title = 'B';
select * from user where title in ('A','B');
commit;

MySQL和Redis事务的区别和用法

问题出现了,这里报出了错误,但是可以看到 前面的 SQL 已经是已执行的了,结果已经发生了变化,从这里看,似乎和 Redis 的处理差不多,除了错误之后语句继续执行。但是 值的注意的是, 在我们实际开发中,这种情况程序会直接抛出异常,以供我们在 catch 块中执行 rollback ,以回滚操作确保数据完整,即使是单独使用 MySQL 命令行 我们也可以用存储过程来对异常进行回滚。

语法错误

刚刚看到 Redis 当遇到 语法错误 时会自动丢弃事务,阻止提交,那 MySQL 呢?

MySQL和Redis事务的区别和用法

答案:不会,MySQL 在顺序执行时,如果未对异常进行处理,总会将成功执行的的提交,而不会触发自动终止,但是我们可以在程序执行时进行放弃提交。

Redis 为什么没有回滚?

Redis 的官方文档给出了这样的解释

// 只有在使用错误的语法调用时才会失败Redis命令(并且在命令排队期间无法检测到问题),或者对于持有错误数据类型的键,Redis命令可能会失败:这意味着实际上失败的命令是编程错误的结果,以及在开发过程中很可能检测到的一种错误,而不是在生产中。

// Redis内部简化且速度更快,因为它不需要回滚的能力。

推荐阅读:
  1. mysql中is 、is not和<=>的区别用法
  2. redis和memcache的区别

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

mysql redis 事务

上一篇:怎样删除php扩展?

下一篇:php中的析构函数和对象引用是什么?

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》