简言:一般来说,事件是必需满足4个前提(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、断绝性(Isolation,又称独立性)、持久性(Durability)。
从题目来看,既然都是事件,那之间有什么区别?来逐一解开,先从两个数据库说去。
MySQL 属于 关联型数据库
, Redis 属于 非关联型数据库
,二者对事件有着差别的诠释。
(相干引荐:MySQL教程,Redis教程)
Redis
[1] Redis 事件能够一次实行多个敕令, 而且带有以下两个主要的保证:
- 批量操纵在发送 EXEC 敕令前被放入行列缓存。
- 收到 EXEC 敕令后进入事件实行,事件中恣意敕令实行失利,其他的敕令依旧被实行。
- 在事件实行历程,其他客户端提交的敕令要求不会插进去到事件实行敕令序列中。
一个事件从最先到实行会阅历以下三个阶段:
- 最先事件。
- 敕令入队。
- 实行事件。
单个 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
.敕令没法进入行列 ,比方 :参数数目毛病,敕令名毛病...,或许某些症结毛病 如内存不足
- A command may fail to be queued, so there may be an error before EXEC is called. For instance the command may be syntactically wrong (wrong number of arguments, wrong command name, ...), or there may be some critical condition like an out of memory condition (if the server is configured to have a memory limit using the
maxmemory
directive).//
2
. 对键举行毛病的操纵 如上面的 对字符串运用 lpush
- A command may fail after EXEC is called, for instance since we performed an operation against a key with the wrong value (like calling a list operation against a string value).
// 客户端搜检键入的敕令,大多数时刻会在挪用
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
列 | 范例 | 解释 |
---|---|---|
id | int(11) 自动增量 | 主键ID |
money | int(11) [0] | 款项 |
title | varchar(500) NULL | 称谓 |
在这里来模仿一个转账的操纵:A
给B
转100元
。
步骤剖析 A
+100 元,B
-100元,即两步虽然很简朴,简朴走一下流程。
能够看到,没有题目,那末我们从中工资的制作一些题目呢?
操纵毛病
列 | 范例 | 解释 |
id | int(11) 自动增量 | |
money | int(11) unsigned [0] |
|
title | varchar(500) NULL |
这里我们把 money
字段变成了无标记,即不能小于 0,而且,调解数据库中的数据以下。
`SELECT * FROM `user` LIMIT 50` (0.000 秒)
修正 | id | money | title |
---|---|---|---|
编辑 | 1 | 10000 | A |
编辑 | 2 | 0 | B |
接着实行下面的 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;
题目涌现了,这里报出了毛病,然则能够看到 前面的 SQL 已是已实行的了,效果已发生了变化,从这里看,好像和 Redis 的处置惩罚差不多,除了毛病以后语句继承实行。然则 值的注重的是, 在我们现实开辟中,这类状况递次会直接抛出非常,以供我们在 catch 块中实行 rollback ,以回滚操纵确保数据完全,纵然是零丁运用 MySQL 敕令行 我们也能够用存储历程来对非常举行回滚。
语法毛病
方才看到 Redis 当碰到 语法毛病
时会自动抛弃事件,阻挠提交,那 MySQL 呢?
答案:不会
,MySQL 在递次实行时,假如未对非常举行处置惩罚,总会将胜利实行的的提交,而不会触发自动停止,然则我们能够在递次实行时举行摒弃提交。
Redis 为何没有回滚?
Redis 的官方文档给出了如许的诠释
// 只要在运用毛病的语法挪用时才会失利Redis敕令(而且在敕令列队时期没法检测到题目),或许关于持有毛病数据范例的键,Redis敕令可能会失利:这意味着现实上失利的敕令是编程毛病的效果,以及在开辟历程当中极可能检测到的一种毛病,而不是在生产中。
- Redis commands can fail only if called with a wrong syntax (and the problem is not detectable during the command queueing), or against keys holding the wrong data type: this means that in practical terms a failing command is the result of a programming errors, and a kind of error that is very likely to be detected during development, and not in production.
// Redis内部简化且速率更快,由于它不须要回滚的才能。
- Redis is internally simplified and faster because it does not need the ability to roll back.
总结
数据库 自动回滚前提 | 操纵毛病 | 语法毛病 |
---|---|---|
MySQL | ✖ | ✖ |
Redis | ✖ | ✔ |
然则 MySQL 支撑手动回滚,现实开辟历程当中能够自行手动对已提交的操纵举行回滚操纵,越发友爱。
以上就是MySQL和Redis事件的比较(图文)的细致内容,更多请关注ki4网别的相干文章!