1. 概要:
他の多くのデータベースと同様、Redis も NoSQL データベースとしてトランザクション メカニズムを提供します。 Redis では、MULTI/EXEC/DISCARD/WATCH の 4 つのコマンドがトランザクション実装の基礎となります。この概念は、リレーショナル データベース開発の経験を持つ開発者にとっては馴染みのないものではないと思いますが、Redis のトランザクションの実装特性を簡単にリストします。
1) トランザクション内のすべてのコマンドは、連続して実行されます。トランザクションの実行中、Redis は他のクライアント要求にサービスを提供しないため、トランザクション内のすべてのコマンドがアトミックに実行されます。
2). リレーショナル データベースのトランザクションと比較して、Redis トランザクションではコマンドの実行が失敗しても、後続のコマンドは引き続き実行されます。
3). MULTI コマンドを通じてトランザクションを開始できます。これは、リレーショナル データベース開発の経験がある人であれば、「BEGIN TRANSACTION」ステートメントとして理解できます。このステートメントの後に実行されるコマンドは、トランザクション内の操作とみなされます。最後に、EXEC/DISCARD コマンドを実行することで、トランザクション内のすべての操作をコミット/ロールバックできます。これら 2 つの Redis コマンドは、リレーショナル データベースの COMMIT/ROLLBACK ステートメントと同等であるとみなすことができます。
4). トランザクションが開始される前に、クライアントとサーバーの間で通信障害が発生し、ネットワークが切断された場合、その後実行されるすべてのステートメントはサーバーによって実行されません。ただし、クライアントが EXEC コマンドを実行した後にネットワーク中断イベントが発生した場合、トランザクション内のすべてのコマンドがサーバーによって実行されます。
5). 追加専用モードを使用する場合、Redis はシステム関数 write を呼び出すことにより、トランザクション内のすべての書き込み操作をディスクに書き込みます。ただし、電源障害によるダウンタイムなど、書き込みプロセス中にシステム クラッシュが発生した場合、その時点ではデータの一部だけがディスクに書き込まれ、データの他の部分が失われる可能性があります。 Redis サーバーは再起動時に必要な一連の整合性チェックを実行し、同様の問題が見つかるとすぐに終了し、対応するエラー プロンプトを表示します。現時点では、Redis ツールキットで提供されている redis-check-aof ツールを最大限に活用する必要があります。このツールは、データの不整合エラーを特定し、書き込まれたデータの一部をロールバックするのに役立ちます。修復後、Redis サーバーを再度再起動できます。
2. 関連コマンドリスト:
コマンドプロトタイプ | 時間複雑さ | コマンドの説明 | 戻り値 |
MULTI | は、その後に実行されるすべてのコマンドは、トランザクションの開始をマークするために使用されます。これらのコマンドは、EXEC の実行時にアトミックに実行されます。 | 常に OK を返します | |
EXEC | 現在の接続のステータスを通常の状態、つまり非トランザクション状態に復元しながら、トランザクション内のコマンド キュー内のすべてのコマンドを実行します。 WATCH コマンドがトランザクション中に実行される場合、EXEC コマンドは、WATCH によって監視されているキーが変更されていない場合にのみ、トランザクション キュー内のすべてのコマンドを実行できます。それ以外の場合、EXEC は現在のトランザクション内のすべてのコマンドを破棄します。 | トランザクション内の各コマンドの結果をアトミックに返します。トランザクションで WATCH が使用されている場合、トランザクションが放棄されると、EXEC は NULL-multi-bulk 応答を返します。 | |
DISCARD | トランザクションキュー内のすべてのコマンドをロールバックし、同時に現在の接続のステータスを通常の状態、つまり非トランザクション状態に戻します。 WATCH コマンドを使用すると、このコマンドはすべてのキーの監視を解除します。 | 常に OK を返します | |
WATCHkey [key...] | O(1) | ただし、監視対象の Key が存在しない場合は、MULTI コマンドを実行する前に監視対象の Key を指定できます。が変更されると、EXEC はトランザクション キュー内のすべてのコマンドの実行を中止します。 | 常にOKを返します。 |
UNWATCH | O(1) | 現在のトランザクションで指定された監視対象キーをキャンセルします。EXEC または DISCARD コマンドが実行される場合、この後、すべての監視対象キーが削除されるため、コマンドを手動で実行する必要はありません。トランザクションキーは自動的にキャンセルされます。 | 常にOKを返します。 |
3. コマンドの例:
1. トランザクションは正常に実行されます:
#在Shell命令行下执行Redis的客户端工具。 /> redis-cli #在当前连接上启动一个新的事务。 redis 127.0.0.1:6379> multi OK #执行事务中的第一条命令,从该命令的返回结果可以看出,该命令并没有立即执行,而是存于事务的命令队列。 redis 127.0.0.1:6379> incr t1 QUEUED #又执行一个新的命令,从结果可以看出,该命令也被存于事务的命令队列。 redis 127.0.0.1:6379> incr t2 QUEUED #执行事务命令队列中的所有命令,从结果可以看出,队列中命令的结果得到返回。 redis 127.0.0.1:6379> exec 1) (integer) 1 2) (integer) 1
2. トランザクションに失敗したコマンドがあります:
#开启一个新的事务。 redis 127.0.0.1:6379> multi OK #设置键a的值为string类型的3。 redis 127.0.0.1:6379> set a 3 QUEUED #从键a所关联的值的头部弹出元素,由于该值是字符串类型,而lpop命令仅能用于List类型,因此在执行exec命令时,该命令将会失败。 redis 127.0.0.1:6379> lpop a QUEUED #再次设置键a的值为字符串4。 redis 127.0.0.1:6379> set a 4 QUEUED #获取键a的值,以便确认该值是否被事务中的第二个set命令设置成功。 redis 127.0.0.1:6379> get a QUEUED #从结果中可以看出,事务中的第二条命令lpop执行失败,而其后的set和get命令均执行成功,这一点是Redis的事务与关系型数据库中的事务之间最为重要的差别。 redis 127.0.0.1:6379> exec 1) OK 2) (error) ERR Operation against a key holding the wrong kind of value 3) OK 4) "4"
#为键t2设置一个事务执行前的值。 redis 127.0.0.1:6379> set t2 tt OK #开启一个事务。 redis 127.0.0.1:6379> multi OK #在事务内为该键设置一个新值。 redis 127.0.0.1:6379> set t2 ttnew QUEUED #放弃事务。 redis 127.0.0.1:6379> discard OK #查看键t2的值,从结果中可以看出该键的值仍为事务开始之前的值。 redis 127.0.0.1:6379> get t2 "tt"
4. WATCH コマンドおよび CAS ベースのオプティミスティック ロック:
Redis トランザクションでは、WATCH コマンドを使用して CAS (チェックアンドセット) 機能を提供できます。トランザクションが実行される前に、WATCH コマンドを通じて複数のキーを監視すると仮定します。WATCH 後にいずれかのキーの値が変更された場合、EXEC コマンドによって実行されたトランザクションは放棄され、呼び出し元に通知するために Null マルチバルク応答が返されます。トランザクションの実行に失敗しました。たとえば、キー値のアトミックなインクリメントを完了するための incr コマンドが Redis に提供されていないと仮定します。この関数を実装したい場合は、対応するコードを自分で記述するしかありません。疑似コードは次のとおりです。
val = GET mykey val = val + 1 SET mykey $val
上記のコードは、単一の接続の場合にのみ実行結果が正しいことを保証できます。これは、複数のクライアントがこのコードを同時に実行している場合、マルチスレッドが発生するためです。プログラムで頻繁に発生するエラー シナリオは競合状態です。たとえば、クライアント A と B の両方が、mykey の元の値を同時に読み取り、その値が 10 であるとします。その後、両方のクライアントが値に 1 を追加して、その値を Redis サーバーに設定し直します。結果は 11 であり、予想していた 12 ではありません。同様の問題を解決するには、WATCH コマンドの助けが必要です。次のコードを参照してください。
WATCH mykey val = GET mykey val = val + 1 MULTI SET mykey $val EXEC
前のコードとの違いは、新しいコードは、mykey の値を取得する前に、まず WATCH コマンドを通じてキーを監視することです。次に set コマンドを使用します。トランザクションに囲まれているため、各接続が EXEC を実行する前に、現在の接続で取得した mykey の値が他の接続されているクライアントによって変更された場合、現在の接続の EXEC コマンドの実行が失敗することが効果的に保証されます。 。このようにして、呼び出し元は戻り値を判断して、val が正常にリセットされたかどうかを知ることができます。
上記は Redis チュートリアル (8): トランザクションの詳細な説明の内容です。さらに関連する内容については、PHP 中国語 Web サイト (www.php.cn) をご覧ください。