悲観的なロックと楽観的なロックについて話します


悲観的なロックと楽観的なロックについて話します
1.出現した背景プログラムにおいて同時的な状況が発生する可能性がある場合、一定の手段によって同時的な状況におけるデータの正確性を保証する必要があり、この手段によって現在のユーザーが他のユーザーと一緒に操作した場合、得られた結果は彼が単独で操作した場合と同じである.この手段を同時制御と呼ぶ.同時制御の目的は、あるユーザの作業が他のユーザの作業に不合理な影響を及ぼさないことを保証することである.
コンカレント制御というのは、一般的にデータベース管理システム(DBMS)に関係しています.DBMSでの同時制御のタスクは、複数のトランザクションがデータベース内の同じデータに同時にアクセスするときに、トランザクションの独立性と統一性、およびデータベースの統一性を損なわないようにすることです.
同時制御を実現する主な手段は,楽観的同時制御と悲観的同時制御の2つに大きく分けることができる.
まず、悲観的なロックでも楽観的なロックでも、人々が定義した概念であり、一つの思想と考えられることを明確にしなければならない.実は関係型データベースシステムに楽観ロックと悲観ロックの概念があるだけでなく、hibernate、tair、memcacheなどにも似たような概念があります.したがって、楽観的なロック、悲観的なロック、その他のデータベース・ロックなどを比較するべきではありません.
2.悲観的なロックデータベース内の1つのデータを変更する場合、同時に他の人に変更されないように、データを直接ロックして同時発生を防ぐのが最善です.このようなデータベース・ロック・メカニズムにより、データを変更する前にロックし、変更する方法を悲観的同時制御と呼ぶ
悲観ロックと呼ばれるのは,データの修正に悲観的な態度を持つ同時制御方式であるからである.データが同時に修正される確率が高いと考えられているので,修正する前にロックをかける必要がある.
悲観ロックは主に共有ロックまたは排他ロックに分けられる.共有ロック【Shared lock】はリードロックとも呼ばれ、Sロックと略称される.名前の通り、共有ロックとは、複数のトランザクションが同じデータに対して1つのロックを共有し、データにアクセスできることですが、読むだけでは変更できません.2.排他ロック【Exclusive lock】はライトロックとも呼ばれ、Xロックと略称される.名前の通り、排他ロックは他のロックと共存できません.トランザクションがデータ行の排他ロックを取得した場合、共有ロックや排他ロックを含む他のトランザクションは取得できませんが、排他ロックを取得したトランザクションはデータ行の読み取りと変更ができます.
しかし、効率的には、ロックを処理するメカニズムにより、データベースに追加のオーバーヘッドが発生し、デッドロックを生成する機会が増加します.また、パラレル性も低下します.1つのトランザクションがロー・データをロックしている場合、他のトランザクションはそのロー・データを処理する前にトランザクションが完了するのを待たなければなりません.
2.楽観ロック楽観ロックは相対的に悲観ロックであり、楽観ロックはデータが一般的に衝突しないと仮定しているので、データが更新されたときに、データの衝突の有無を正式に検出し、衝突が発見された場合、ユーザーに誤った情報を返し、ユーザーにどのようにするかを決定させる.
悲観的なロックに対して、データベースを処理する場合、楽観的なロックはデータベースが提供するロックメカニズムを使用しません.一般的な楽観的なロックを実現する方法は、データバージョンを記録することです.
楽観的な同時制御は、トランザクション間のデータ競合(data race)の確率が比較的小さいと信じているため、コミット時までロックするため、ロックやデッドロックは発生しません.
3.実現方式(1)悲観ロック実現方式悲観ロックの実現は、データベースが提供するロックメカニズムに依存することが多い.データベースでは、悲観的なロックの流れは次のとおりです.1.レコードを変更する前に、そのレコードに排他ロック(exclusive locking)を追加してみます.2.ロックが失敗した場合、レコードが変更されていることを示す場合、現在のクエリは例外を待機または放出する可能性があります.具体的な応答方式は開発者が実際の必要に応じて決定する.3.ロックが正常に追加されると、レコードを変更でき、トランザクションが完了するとロックが解除されます.4.期間中、他のレコードを変更または排他的にロックする操作がある場合は、ロックの解除または異常の直接放出を待機します.
よく使われるMySql Innodbエンジンの例を挙げて、SQLで悲観的なロックをどのように使用するかを説明します.
悲観的ロックを使用するには、MySQLデータベースの自動コミットプロパティを閉じる必要があります.MySQLではautocommitモードがデフォルトで使用されているため、更新操作を実行するとすぐに結果がコミットされます.(sql文:set autocommit=0)
次の例を見てみましょう.
//    
begin;
//         
select m from items where id=1 for update;
//       2
update items set m=2 where id = 1;
//    
commit;

以上,id=1のレコードを修正する前にfor updateでロックしてから修正する.これが典型的な悲観的なロック戦略です.
上記の変更在庫のコードが同時発生した場合、同じ時間にトランザクションを開いてid=1のロックを取得できるスレッドは1つしかありません.他のトランザクションは、今回のトランザクションのコミット後に実行する必要があります.これにより、現在のデータが他のトランザクションによって変更されないことが保証されます.
前述したように、select...for updateを使用するとデータがロックされますが、いくつかのロックのレベルに注意する必要があります.MySQL InnoDBのデフォルトの行レベルロックです.行レベルのロックはすべてインデックスに基づいており、SQL文がインデックスを使用しないと行レベルのロックは使用されません.テーブルレベルのロックを使用してテーブル全体をロックすることに注意してください.
(2)楽観ロックの使用方法楽観ロックを使用すると,データベースのロックメカニズムを利用する必要がなくなる.
楽観的なロックの概念の中で実はすでにその具体的な実現の細部を述べた.主に、競合検出とデータ更新の2つのステップです.その実現方式の1つの比較的典型的なものはCAS(Compare and Swap)である.
CASは楽観的なロック技術で、複数のスレッドがCASを使用して同じ変数を同時に更新しようとすると、そのうちの1つのスレッドだけが変数の値を更新することができ、他のスレッドは失敗し、失敗したスレッドは掛けられず、今回の競争で失敗したことを通知され、再び試みることができます.
次の例を見てください.

//         ,m=3
select m from items where id = 1
//       2
update items set m=2 where id = 1 and m =3;

以上、更新する前に、在庫表の現在在庫数(m)を照会し、updateを行う際に在庫数を修正条件とします.更新が発行されると、データベーステーブルに対応するレコードの現在在庫数と1回目に取り出した在庫数とを比較し、データベーステーブルの現在在庫数と1回目に取り出した在庫数が等しい場合は更新し、そうでなければ期限切れデータとみなす.
以上の更新文には、伝説のABA問題という比較的重要な問題があります.
例えば、あるスレッドoneがデータベースから在庫数3を取り出すと、別のスレッドtwoもデータベースから在庫数3を取り出し、twoはいくつかの操作を行って2になり、twoはまた在庫数を3にし、スレッドoneがCAS操作を行うとデータベースは依然として3であり、one操作に成功する.スレッドoneのCAS操作は成功したが,このプロセスに問題がないわけではない.
ABA問題を解決するには、個別に順次増加可能なversionフィールドを介して比較的良い方法がある.次の方法に変更します.
楽観ロックは、データの変更操作を実行するたびに、前のバージョン番号を付けます.バージョン番号とデータのバージョン番号が一致すると、変更操作を実行し、バージョン番号に+1操作を実行できます.そうしないと、実行に失敗します.操作するたびにバージョン番号が増加するため、ABAの問題は発生しません.バージョン番号が増加するだけで減少しません.
versionに加えて、タイムスタンプは天然に順序的に増加するため、タイムスタンプを使用することもできます.
以上のSQLでは、高同時性に遭遇すると、1つのスレッドだけが修正に成功すると、多くの失敗が発生します.宝を洗うような電子商取引サイトでは、高合併はよくあることで、ユーザーに失敗を感じさせるのは明らかに合理的ではない.だから、楽観的なロックの粒度を減らす方法を考えなければなりません.楽観錠の力を減らし、スループットを最大限に向上させ、同時能力を高めることができるという良いアドバイスがあります.次のようになります.
//      
update item
set m=m-1
where id =1 and m-1>0

以上のSQL文では、ユーザーの下単数が1の場合、quantity-1>0で楽観的なロック制御を行います.
以上のupdate文は、実行中に1回の原子操作でquantityの値を自分でクエリーし、1を減算します.
高同時環境でのロック粒度制御は重要な学問であり、良いロックを選択し、データの安全を保証する場合、スループットを大幅に向上させ、さらに性能を向上させることができる.
4.楽観ロックと悲観ロックの選択の上で、主に両者の違いと適用シーンを見ればいい.1.楽観ロックは本当にロックされておらず、効率が高い.ロックの粒度が把握できないと、更新に失敗する確率が高くなり、ビジネスに失敗しやすくなります.2.悲観ロックはデータベースロックに依存し、効率が低い.更新に失敗する確率は低い.
インターネットの3つの高アーキテクチャ(高同時性、高性能、高可用性)の提案に伴い、悲観的なロックは生産環境、特に同時性の高いビジネスシーンに応用されることが少なくなっています.