この記事の内容は、MySQL と Redis のトランザクションの比較 (写真とテキスト) に関するもので、一定の参考価値があります。必要な友人が参考にすることができます。お役に立てれば幸いです。
要約: 一般に、トランザクションは 4 つの条件 (ACID) を満たす必要があります。アトミック性 (A トミシティ、または分割不可能性)、一貫性 (C一貫性)、分離 (##) #I孤立、独立としても知られています)、耐久性(Durability)。
タイトルから判断すると、どちらもトランザクションなので、両者の違いは何でしょうか? 2 つのデータベースから始めて、1 つずつ紐解いていきましょう。 MySQL はリレーショナル データベース に属し、Redis は
非リレーショナル データベース に属しており、トランザクションの解釈が異なります。
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上記のトランザクションでは、
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 が存在し、値が出力されていることがわかります。このとき、
操作エラーが発生しても、エラーは発生しないことがわかりました。
いいえ 実行が停止され、エラー後のステートメントも実行されて正常に実行されます。これは、上記の内容と一致しているようです。 途中で特定の命令が失敗しても、エラーは発生しません。前の命令のロールバックが発生するだけでなく、後続の命令も発生しません。これは行わないでください。
構文エラー
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)実行時
No の設定時にパラメータが指定され、2 回目の実行時に 1 つのパラメータが意図的に指定されました。
構文エラーが報告され、トランザクションが最終的に送信されたことがわかります。これにより、エラーによりトランザクションが失われたことがわかります。その後、
keys * を使用して検索し、これが実際に当てはまることがわかりました。
トランザクション内のエラーを見つけることができます// 実行中に発生する可能性があります2 つの間違ったコマンド エラーが発生します。 トランザクション中に、次の 2 種類のコマンド エラーが発生する可能性があります://1
コマンドはキューに入力できません。たとえば、番号が間違っています。パラメータの不足、間違ったコマンド名 ...、またはメモリ不足などの重大なエラー
コマンドがキューに入れられない可能性があるため、EXEC が呼び出される前にエラーが発生する可能性があります。たとえば、次のコマンドです。構文的に間違っている可能性があります (引数の数が間違っている、コマンド名が間違っているなど)。または、メモリ不足状態などの重大な状態が存在する可能性があります (サーバーが
2- maxmemory# を使用してメモリ制限を持つように構成されている場合) ##directive).
//
。上記の文字列で lpush を使用するなど、キーに対して間違った操作を実行します。
after##コマンドが失敗する可能性があります
たとえば、間違った値のキーに対して操作を実行したため (文字列値に対してリスト操作を呼び出すなど)、EXEC が呼び出されます。
を呼び出す前に- // クライアント入力されたコマンドをチェックします。ほとんどの場合、
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 只有 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 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 トランザクションの比較 (写真とテキスト)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。