入門
で、深さの時間の前にデータベース理論の理解、我々は別のトランザクション分離レベルに可能性のある問題を学びました。より良いこれらの問題を再現するためにMySQLデータベースのテストでそれを理解するために。汚れについて読み、隔離の適切なレベルでは非反復可能読み取りを再現するのは非常に簡単です。
しかし、ファントム読み取りのために、私が見つかりました。それは、完了した取引されているものを読んでのMySQLの魔法ということを考え、反復可能読み取り分離レベルに表示されませんか?
テスト:
テスト表deptを作成します。
CREATETABLE`dept`(`id`int(11)NOTNULLAUTO_INCREMENT,`name`varchar(20)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=12DEFAULTCHARSET=utf8insertintodept(name)values("后勤部")
以上の処理の実行によれば、(2によって提出された取引データを含む)は、2つのデータは、第2選択クエリ、最初のトランザクションデータアウトクエリを選択することが期待されるべきです。
しかし、実際のテストで発見したことは、実際にのみ秒でデータクエリ処理を選択します。これはですが、これは状況は発生しないはずであるデータベース理論(排他ロックと共有ロック)の反復可能読み取りを実現するために従いました。
より具体的な上の理由で事務の理論のもと、私たちの前に最初のレビュー。
データベース理論の原則
業務
トランザクション(トランザクション)は、一般的に行うのか、行っているものを指します。この用語は、コンピュータがプログラム実行部データアイテム(ユニット)の様々なデータベースにアクセスして更新することができることを意味します。業務トランザクションによって始まる(トランザクションの開始)、トランザクションは(エンドトランザクション)組成物との間で行われるすべての操作を終了します。
リレーショナルデータベースでは、トランザクションは、SQL文またはプログラム全体のセットです。
なぜべきトランザクション
データベーストランザクションは、典型的には、データベースの読み取りや書き込みの一連の操作が含まれています。その存在は、次の2つの目的があります。
- データベースの正常な動作の障害から回復する方法を提供し、データベースはまた、異常な状態のままコヒーレンシを維持するための方法を提供します。
- データベースへの同時アクセスのための複数のアプリケーションが互いの動作を保証するために、アプリケーション間の分離方法を提供することができるときに互いに干渉する。
トランザクションのプロパティ
原子性、一貫性、分離性、耐久性:トランザクションは、4つのプロパティを持ちます。これらの4つのプロパティは、通常、ACID特性と呼ばれます。
- アトミック(不可分):トランザクションは、ワークユニットの不可欠な部分であるべきで、トランザクションは、操作が成功または成功していない含みます。
- 一貫性(一貫性):データベーストランザクションをもたらすためには、別の一貫した状態にある一貫した状態から変更する必要があります。一貫性とアトミック性は密接に関連しています。
- 分離(隔離):トランザクションの実行は、他のトランザクション干渉することはできません。すなわち、操作及び取引前取引内部データの使用は、単離されている他の同時トランザクションにコミットされておらず、それぞれ互いに同時に実行トランザクションに影響を与えることができません。
- 持続性(耐久性):トランザクションが正常に送信されると、永久である必要があり、データベース内のデータを変更します。次の操作またはその他の障害は、それらに影響を持つべきではありません。
トランザクションのいくつかの特徴は、グループの概念との間に等しくありません。
いつでも限り、あなたはアトミックの一貫性を保証することができますのように自然なバリア性を、ある1つのトランザクションのみ、存在する場合。
同時性の存在した場合、我々は一貫性を確保するためにアトミックとの絶縁を確保する必要があります。
同時トランザクションでのデータベースの問題
あなたはトランザクション分離を考慮していない場合は、次のような問題が発生します。
ダーティー読み取り
ダーティ・リードトランザクションは、データが他にコミットされていないトランザクションが読み出される過程を指します。トランザクションがデータを複数回変更されますが、このトランザクションの変更がデータにアクセスするための同時トランザクションその後、コミットされていないで、この何度もされている場合、それは結果データの不整合二つのトランザクションが発生します。
非反復可能読み取り
データベース内のデータの特定の部分のための非反復読み出し手段は、複数のトランザクションクエリはデータ値の異なる範囲を返す(ここでの違いは、一貫性のない1つ以上のコンテンツデータが、データの同じ番号を参照)、そのクエリ間隔は、トランザクションデータが改訂され、他のトランザクションに提出する必要があります。
読書を繰り返し、非読み出し差が汚れている、非反復可能読み取りが提出され、他のトランザクションから読み込まれながら、汚れの読み取りトランザクションは、別のコミットされていないトランザクションからのダーティデータを読み込むです。いくつかのケースでは、非反復可能読み取りが問題ではないことに注意してください。
マジック読書
魔法の読書は、トランザクションが非独立した実行起こる現象です。例えば、すべての行のテーブル内のデータ項目にトランザクションT1は、操作の「2」から「1」に作られたが、今回は表の行の値は、データ項目、データ項目およびトランザクションT2に挿入されますまたは「1」とデータベースにコミット。
私たちはデータを修正するかどうかを確認するために、トランザクションT1のユーザーの操作は、あなたが変更していない行があるでしょう、実際には、このラインは、これはファントム読み取り起こったことである、のような、幻覚のように、トランザクションT2から追加されます。
ファントム読み取りおよび非反復可能読み取り(これはダーティ・リードとは異なる)別のトランザクションが送信された読み出され、差は、非反復可能読み取りが更新で発生することがありされ、削除操作、およびファントムリードは、挿入操作で発生します。
排他ロック、共有ロック
また、Xロック、書き込みロックとして知られている排他ロック(排他)、。
また、Sロック、読取りロックとして知られている共有ロック(共有)。
リーダーロックとの間に次の関係があります。
- O SロックOを添加したトランザクションデータオブジェクトが実行されてもよいが、操作を更新することができない操作を読み取ります。O Sを添加するが、Xロックを追加することができないロックすることができ、他のトランザクションのロック時。
- あなたはO.を読み、更新することができ、トランザクション・データ・オブジェクト・OプラスXロック、ロックO中の他のトランザクションはロックを追加することはできません。
読み取りよりシングルライト:、リーダーロックとの関係は、のように要約することができるされていること
トランザクション分離レベル
トランザクション分離レベルでいくつかあります。
非コミット読み取り(READ UNCOMMITTED)
この問題を解決するアップデートを失いました。もしトランザクションは、それが他の事項が同時に書き込みを許可していませんので、書き込みを始めますが、他のトランザクションがトリップデータを読み取ることができました。分離レベルは、これらのデータに加えてXをロックする必要があり、いくつかのデータに変更する、すなわちトランザクションの必要性を達成するために、「排他的な書き込みロック」でSロックを追加する必要はありませんデータを読み取ることができます。
コミットを読む(READ COMMITTED)
ダーティ・リードの問題を解決します。読み出しデータトランザクションが他のトランザクションがデータの行へのアクセスを継続できますが、書き込みコミットされていないトランザクションが行にアクセスすることから、他のトランザクションを防ぐことができます。データが完了したことを読んで、すぐ後に、「ロックを読んで共用瞬間」と「排他書き込みロックが」によって達成される。これは、これらのデータをロックに変更されるトランザクションのニーズはXを追加しなければならないこと、することができ、プラス時間は、いくつかのデータをデータSロックを読み取るために必要なSロック解除は、トランザクションが終了するまで待つことはありません。
反復可能読み取り(反復可能読み取り)
禁止非反復読み取り及びダーティ・リード、時にはファントムリードデータが発生する場合があります。読み出しデータトランザクションが書き込みトランザクション(ただし、読み取りトランザクションを可能にすること)によって禁止されて、書き込みトランザクションは、他の取引を禁止します。
デフォルトの分離レベルを使用してMySQLの。これは、「共有読み取りロック」を通って、いくつかの事項は、データがすぐに完了し読まれていない場合、データを読み込むとき、あなたはSロックを追加する必要があり、これらのデータに加えてXをロックする必要があり、データを修正する必要があることを認識し、「彼は、行ロックを書きました」トランザクションのリリースが終了するまでSロック解除、しかし、待って。
シリアライズ(直列化)
読書の魔法の問題を解決します。厳格なトランザクション分離を提供します。これは、トランザクションが同時にではなく、1で行うことができ、トランザクションのシリアル化が必要。専用トランザクションのシリアル化を達成することができない「ロック行レベル」を介して、新たに挿入されたデータは、単に他のメカニズムを介しての取引照会アクセスを実行していないことを確認しなければなりません。
MySQLの分離レベルの実装
上記ではない完全達成するために、上述した理論に従って、パフォーマンス上の理由から、データベース理論の概念のいくつかの説明が、そのようなデータベースでのMySQL、ORACLE、です。
MVCC
マルチバージョン同時実行制御(マルチバージョン同時実行制御、MVCC)理論的な方法を達成するためのMySQLベースの楽観的ロックの分離レベルで、かつ読み取りを実現するために反復可能読み取り分離レベルを達成することができますコミット。
実装(分離レベルが反復可能読み取りです)
それは二つの概念の導入を達成するためにどのように来る前に:
- システムのバージョン番号:増分数、それぞれが新しいトランザクションを開始するには、システムが自動的にバージョン番号をインクリメントします。
- Servicesバージョン:トランザクションの開始時にシステムのバージョン番号。
MySQLでは、次のデータの各テーブルに2つのフィールドを追加します。
- バージョン番号を作成:作成するために割り当てられた現在のバージョン番号などのデータの行、システムのバージョン番号を作成する場合
- バージョン番号を削除:データの行を削除すると、削除されたバージョン番号など、現在のシステムのバージョン番号が割り当てられています
選択する
データの読み出しを選択した場合のルールは以下のとおりです。現在のトランザクションのバージョン番号を<、=現在のトランザクションのバージョン番号バージョン番号が空の削除または>バージョン番号を作成します。
バージョン番号を作成<=現在のトランザクションのバージョン番号は、トランザクションの開始後のデータのうちデータが作成されていないことを確認します。これは、なぜ最初の例では、我々は後から追加されたデータの原因を見つけることができませんで
トランザクションがオープンされる前に、少なくともデータが削除されていないことを確認するために>現在のトランザクションのバージョン番号をバージョン番号が空で削除するか、または、それがデータをチェックアウトする必要があります。
インサート
インサートは、バージョン番号フィールドを作成するために割り当てられている現在のシステムのバージョン番号です。
更新
行に元のバージョンを削除するには、現在のトランザクションを維持しながら、作成された行のバージョン番号である現在のトランザクションバージョン保存、新しいレコードを挿入し、実際には、ここでの更新は、削除によるものであり、達成するために挿入します。
DELETE
あなたは、バージョン番号フィールドを削除するために割り当てられている現在のシステムのバージョン番号を削除すると場所が実際にコミットされた場合でも、識別はトランザクションで削除された行は、データが削除されません。規則によると、データを選択すると、データを照会するオープンされません。
MVCCは本当にファントム読み取りを解決しますか?
この連載は、重要性を欠い読み、質問とテストを続けるように見えるので、非常にサポートし始めて私たちの理論の試験例およびこのような観点からは、MySQLではMVCCによって読み取らファントムの問題を解決しているようです。
テストデータの前に:
我々の期待以上の結果を踏まえた結果がこれです:
財務部2 R&D idname1
但是实际上我们的经过是:
本来我们希望得到的结果只是第一条数据的部门改为财务,但是结果确实两条数据都被修改了。
这种结果告诉我们其实在MySQL可重复读的隔离级别中并不是完全解决了幻读的问题,而是解决了读数据情况下的幻读问题。而对于修改的操作依旧存在幻读问题,就是说MVCC对于幻读的解决时不彻底的。
快照读和当前读
出现了上面的情况我们需要知道为什么会出现这种情况。在查阅了一些资料后发现在RR级别中,通过MVCC机制,虽然让数据变得可重复读,但我们读到的数据可能是历史数据,不是数据库最新的数据。
这种读取历史数据的方式,我们叫它快照读 (snapshot read),而读取数据库最新版本数据的方式,叫当前读 (current read)。
select 快照读
当执行select操作是innodb默认会执行快照读,会记录下这次select后的结果,之后select 的时候就会返回这次快照的数据,即使其他事务提交了不会影响当前select的数据,这就实现了可重复读了。
快照的生成当在第一次执行select的时候,也就是说假设当A开启了事务,然后没有执行任何操作,这时候B insert了一条数据然后commit,这时候A执行 select,那么返回的数据中就会有B添加的那条数据。
之后无论再有其他事务commit都没有关系,因为快照已经生成了,后面的select都是根据快照来的。
当前读
对于会对数据修改的操作(update、insert、delete)都是采用当前读的模式。在执行这几个操作时会读取最新的记录,即使是别的事务提交的数据也可以查询到。
假设要update一条记录,但是在另一个事务中已经delete掉这条数据并且commit了,如果update就会产生冲突,所以在update的时候需要知道最新的数据。也正是因为这样所以才导致上面我们测试的那种情况。
select的当前读需要手动的加锁:
select*fromtablewhere?lockinsharemode;select*fromtablewhere?forupdate;
有个问题说明下
試験中、始まりは私が使用しては非常に最初のトランザクション1の初めから第二のテストの上、取引トランザクション1の結果は、2つの新しいデータを発見した、文がトランザクションの開始で始まり、それは考えられていたと思いましたそして、MVCCの前に選択矛盾を支配するので、次のテストを実行します。
SELECT*FROMinformation_schema.INNODB_TRX//用于查询当前正在执行中的事务
あなたが見ることができる場合にのみ始まる文は、実際に事業を開始しません。
開始を選択した後、次のステートメントを追加します。
だから、実際にビジネスを開く前に変更して再検索して他の操作へのデータの追加および削除を理解します。
ファントム読み取りを解決する方法
明らかに反復可能読み取り分離レベルを完全ファントム読み取りの問題を解決する方法はありません、我々はファントム読み取りを解決するためのプロジェクトならば、2つの方法があります。
- シリアルリード分離レベルを使用します
- MVCC +ネクストキーロック:ネクストキーロックは、レコード・ロック(ロックインデックス)とギャップロック(ギャップロックは、各ロック用データにのみ必要ではなく、また、近いデータは、データをラッチします)
実際には、多くのプロジェクトは、二つの方法の上に使用することはありませんシリアライズの読み出し性能が悪く、実際には、ファントムは、私たちが受け入れることができることを何度も読みました。