この記事では、データベースのトランザクションとロックに関する関連知識を詳しく紹介します。主にいくつかの概念的なことは退屈に思えるかもしれませんが、資格のあるプログラマーとして、それらを習得する必要がありますし、そうしなければなりません。この理論的な知識は、私たちが普段コードを書くときの内面の強さのようなものであり、内面と外面の両方のスキルを練習し、お互いを高め合うことによってのみ、武道の達人のレベルに達することができます。さて、早速始めましょう。
データベーストランザクション
トランザクションの境界
トランザクションの開始境界(開始)
トランザクションの終了境界(コミット): トランザクションを送信し、トランザクションによって更新されたデータベースの状態を永続的に保存します。
トランザクションの異常終了境界(ロールバック):トランザクションを取り消し、データベースをトランザクション実行前の初期状態に戻します。
MySQL.exe プログラムを起動するたびに、別のデータベース接続が確立されます。各データベース接続には、現在のトランザクション モードを表すグローバル変数 autocommit があり、これには 2 つのオプションの値があります:
0: 手動コミット モードを表します
1: 自動コミット モードを表し、デフォルト値
Weこの値を表示および変更できます。
データベーストランザクション (ACID) の 4 つの特性:
原子性: トランザクションはアトミックな操作単位であり、データに対する変更はすべて実行されるか、まったく実行されないかのいずれかです。
一貫性 一貫性: データは維持される必要があります。トランザクションの開始時と完了時の一貫性。
分離: データベース システムは、トランザクションが外部の同時実行から「独立」していることを保証します。
持続性: トランザクションの完了後。 、データへの変更は永続的であり、システム障害が発生した場合でも維持できます。
トランザクション分離レベル
データベーストランザクション分離レベルは、トランザクションが他のトランザクションの中間結果を読み取ることができるかどうかのみを意味します。
Read Uncommitted (コミットされていないコンテンツの読み取り)
この分離レベルでは、すべてのトランザクションは他のコミットされていないトランザクションの実行結果を確認できます。この分離レベルは他のレベルと比べてパフォーマンスがそれほど優れていないため、実際のアプリケーションではほとんど使用されません。コミットされていないデータの読み取りは、ダーティ リードとも呼ばれます。
Read Committed
これは、ほとんどのデータベース システムのデフォルトの分離レベルです (ただし、MySQL のデフォルトではありません)。これは分離の単純な定義を満たしています。つまり、トランザクションはコミットされたトランザクションによって行われた変更のみを確認できます。この分離レベルは、いわゆる非反復読み取りもサポートします。これは、同じトランザクションの他のインスタンスがこのインスタンスの処理中に新しいコミットを持つ可能性があるため、同じ選択が異なる結果を返す可能性があるためです。
Repeatable Read
これは、MySQL のデフォルトのトランザクション分離レベルであり、データを同時に読み取るときに、同じトランザクションの複数のインスタンスが同じデータ行を参照できるようにします。ただし、理論的には、これはファントム リード (ファントム リード) という別のやっかいな問題につながります。簡単に言えば、ファントム読み取りとは、ユーザーが特定の範囲のデータ行を読み取るときに、別のトランザクションがその範囲に新しい行を挿入することを意味します。ユーザーがその範囲内のデータ行を再度読み取ると、新しい行があることがわかります。 " わかりました。 InnoDB および Falcon ストレージ エンジンは、Multiversion Concurrency Control (MVCC) メカニズムを通じてこの問題を解決します。
シリアル化可能
これは、トランザクションが互いに競合しないように強制的に順序付けすることで、ファントム読み取りの問題を解決します。つまり、読み取られた各データ行に共有ロックが追加されます。このレベルでは、多数のタイムアウトやロック競合が発生する可能性があります。
分離レベルが高くなるほど、データの完全性と一貫性が保証されますが、同時実行パフォーマンスへの影響は大きくなります。ほとんどのアプリケーションでは、データベース システムの分離レベルを Read Committed に設定することを効果的に検討できます。これにより、ダーティ リードが回避され、同時実行パフォーマンスが向上します。これにより、反復不可能な読み取り、無駄な更新、第 2 タイプの更新の喪失などの同時実行性の問題が発生しますが、そのような問題が発生する可能性がある個別の状況では、アプリケーションが悲観的ロックと楽観的ロックを使用して制御できます。
現在実行中のトランザクションを追加します。現在のトランザクションが存在しない場合は、新しいトランザクションを開始します。 Spring オペレーティング データベースのデフォルトのトランザクション伝播動作は propagation_required です。
現在トランザクション内にある場合は、トランザクションとして実行されます。
トランザクション内で実行する必要があります。 。つまり、親トランザクションによってのみ呼び出すことができます。それ以外の場合は、例外がスローされます。
現在のトランザクションを一時停止し、新しいトランザクションを開始します。
をトランザクション内で実行すると、例外がスローされます。
ネストされたトランザクションは親トランザクションに依存します。親トランザクションがコミットされると、親トランザクションもロールバックされます。
ページ レベル: エンジン BDB、一度に隣接するレコードのグループをロックします。
テーブル レベル: エンジン MyISAM。テーブル全体をロックするものとして理解され、同時に読み取ることはできますが、書き込むことはできません。
3 種類のロックの特徴は次のように大まかに要約できます:
1) テーブルレベルのロック: 低いオーバーヘッド、高速なロック、大きなロック粒度、最も高いロック競合確率、最も低い同時実行性。
2) 行レベルのロック: オーバーヘッドが高く、ロックが遅い。ロックの粒度が最も小さく、ロックの競合の可能性が最も低く、同時実行性も最も高い。
3) ページ ロック: オーバーヘッドとロック時間はテーブル ロックと行ロックの間であり、デッドロックが発生します。ロックの粒度はテーブル ロックと行ロックの間であり、同時実行性は平均的です。
ENGINE = InnoDB AUTO_INCREMENT=10 DEFAULT CHARACTER SET = utf8 comment='用户表エンジンを InnoDB に設定します。InnnoDB は他のエンジンとは異なります。まず、トランザクション (TRANCSACTION) をサポートし、次に行レベルのロックを使用します。
InnoDB中两种模式的行级锁:
1)共享锁:允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
( Select * from table_name where ……lock in share mode)
2)排他锁:允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和 排他写锁。(select * from table_name where…..for update)
为了允许行锁和表锁共存,实现多粒度锁机制;同时还有两种内部使用的意向锁(都是表锁),分别为意向共享锁和意向排他锁。
意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
注意:InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点与Oracle不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!MySQL的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的。应用设计的时候要注意这一点。
行级锁的优缺点
行级锁定的优点:
当在许多线程中访问不同的行时只存在少量锁定冲突。
回滚时只有少量的更改。
可以长时间锁定单一的行。
行级锁定的缺点:
比页级或表级锁定占用更多的内存。
当在表的大部分数据上使用时,比页级或表级锁定速度慢,因为你必须获取更多的锁。如果你在大部分数据上经常进行GROUP BY操作或
者必须经常扫描整个表,比其它锁定明显慢很多。
hibernate中通过行级锁实现的悲观锁。
一些例子:
假设有个表单products ,里面有id跟name二个栏位,id是主键。
1: 明确指定主键,并且有此条记录,执行row lock。若查无此记录,无lock。
SELECT * FROM products WHERE id='3' FOR UPDATE;SELECT * FROM products WHERE id='3' and name="cat" FOR UPDATE;
2: 无主键,执行table lock。
SELECT * FROM products WHERE name='Mouse' FOR UPDATE;
3: 主键不明确,table lock。
SELECT * FROM products WHERE id<>'3' FOR UPDATE;
注意: FOR UPDATE仅适用于InnoDB,且必须在事务块(BEGIN/COMMIT)中才能生效。此外,如果A与B都对表id进行查询但查询不到记录,则A与B在查询上不会进行row锁,但A与B都会获取排它锁,此时A再插入一条记录的话则会因为B已经有锁而处于等待中,此时B再插入一条同样的数据则会抛出Deadlock found when trying to get lock; try restarting transaction。然后释放锁,此时A就获得了锁而插入成功。
以上就是MySQL中的事务与锁的内容,更多相关内容请关注PHP中文网(www.php.cn)!