ホームページ >データベース >mysql チュートリアル >データベーストランザクションとMySQLトランザクションの概要
mysql チュートリアルデータベース トランザクションと MySQL トランザクションの概要
推奨 (無料): mysql チュートリアル
トランザクション機能: ACID
ビジネスの観点から見ると、一連のデータベース操作は、4 つの特性を維持するために必要です:
ACID をより深く理解するために、例として銀行口座振替を取り上げます。
START TRANSACTION;SELECT balance FROM checking WHERE customer_id = 10233276;UPDATE checking SET balance = balance - 200.00 WHERE customer_id = 10233276;UPDATE savings SET balance = balance + 200.00 WHERE customer_id = 10233276;COMMIT;
#トランザクション分離レベル
同時トランザクションによって引き起こされる問題
ファントム リーディングと反復不可能なリーディングの違い:
トランザクションの同時処理によって引き起こされる問題の解決策:
「更新の喪失」は一般に、完全に避けるべきものです。ただし、更新消失の防止はデータベーストランザクションコントローラだけで解決できるものではなく、アプリケーション側で更新対象のデータに必要なロックを付与する必要があるため、更新消失の防止はアプリケーション側で行う必要があります。
「ダーティ リード」、「反復不可能な読み取り」、および「ファントム リード」は、実際にはデータベースの読み取り一貫性の問題であり、データベースが特定のトランザクション分離メカニズムを提供することで解決する必要があります。
#レベル 1: コミットされていない読み取り (コミットされていないコンテンツの読み取り)
すべてのトランザクションは他のコミットされていないトランザクションの実行結果を確認できますこれは、ほとんどのデータベース システムのデフォルトの分離レベルです (ただし、MySQL のデフォルトではありません)
これは分離の単純な定義を満たしています。トランザクションはトランザクションによってコミットされたもののみを確認できます。
この分離レベルの変更に関する問題は、次のとおりです。反復不可能な読み取り: 反復不可能な読み取りとは、同じトランザクションでまったく同じ選択ステートメントを実行すると、異なる結果が表示される可能性があることを意味します。この状況の考えられる理由は次のとおりです:
新しいコミットによるクロス トランザクションがあり、データ変更が発生します;
aデータベースは複数のインスタンスによって操作されており、同じトランザクションの他のインスタンスがインスタンスの処理中に新しいコミットを行う可能性があります
これは MySQL のデフォルトのトランザクション分離レベルです。データを同時に読み取るときに、同じトランザクションの複数のインスタンスに同じメッセージが表示されるようにします。データ行
MVCC は、特定の時点でのデータのスナップショットを保存することによって実装されます。言い換えれば、実装にどれだけ時間がかかっても、それぞれのモノから得られるデータには一貫性があるということです。 オプティミスティック同時実行制御とペシミスティック同時実行制御に分かれます。
MVCC の仕組み:
InnoDB の MVCC は、レコードの各行の背後に 2 つの非表示列を保存することによって実装されます。これら 2 つの列の 1 つは行の作成時刻を格納し、もう 1 つは行の有効期限 (削除時刻) を格納します。もちろん、保存されるのはリアルタイムではなく、システムのバージョン番号です。新しいトランザクションが開始されるたびに、システムのバージョン番号が自動的に追加されます。トランザクション開始時のシステム バージョン番号は、トランザクションのバージョン番号として使用され、比較のためにレコードの各行のバージョン番号をクエリするために使用されます。REPEATABLE READ 分離レベルでの MVCC の動作:
#InnoDB は、次の条件に従ってレコードの各行をチェックします。
これら 2 つのバージョン番号を保存すると、ほとんどの操作でロックが必要なくなります。これにより、データ操作がシンプルになり、パフォーマンスが向上し、複雑な要件に必要な行のみが確実に読み取られるようになります。欠点は、レコードの各行に追加の記憶域スペース、より多くの行チェック、および追加のメンテナンス作業が必要になることです。
MVCC は、COMMITTED READ (読み取り送信) と REPEATABLE READ (反復読み取り) の 2 つの分離レベルでのみ機能します。
MVCC は行レベルのロックの一種であると考えられますが、多くの場合ロック操作が回避され、オーバーヘッドが低くなります。データベースごとに実装メカニズムは異なりますが、ほとんどのデータベースではノンブロッキング読み取り操作 (読み取りにロックは必要なく、非反復読み取りとファントム読み取りを回避できます) が実装され、書き込み操作は必要な行のみをロックします (書き込みは必ずロックする必要があります)。ロックされている場合)、そうでない場合は、異なるトランザクションによる同時書き込みによりデータの不整合が発生します)。
レベル 4: シリアル化可能
これは最高の分離レベルです分離レベルの比較
各データベースでは、上記の 4 つの分離レベルが完全に実装されていない可能性があります。例:
#トランザクション ログトランザクション ログは、トランザクション効率の向上に役立ちます。 :
トランザクション ログを使用すると、ストレージ エンジンはテーブル データを変更するときにメモリ コピーを変更するだけで済み、その代わりに、ハード ディスクに保存されているトランザクション ログに変更動作を記録します。変更されたデータ自体はディスクに永続化されます。
トランザクションの実装は、データベースのストレージ エンジンに基づいています。ストレージ エンジンが異なれば、トランザクションのサポート レベルも異なります。 mysql のトランザクションをサポートするストレージ エンジンには、innoDB と NDB が含まれます。 innoDB は、mysql のデフォルトのストレージ エンジンです。デフォルトの分離レベルは RR (Repeatable Read) であり、マルチバージョン
同時実行制御を通じて RR の分離レベルをさらに一歩進めています(MVCC、Multiversion Concurrency Control) は非反復読み取り問題を解決し、ギャップ ロック (つまり、同時実行制御) はファントム読み取りの問題を解決します。したがって、innoDB の RR 分離レベルは実際にはシリアル化レベルの効果を実現し、比較的良好な同時実行パフォーマンスを維持します。
事务的隔离性是通过锁实现,而事务的原子性、一致性和持久性则是通过事务日志实现。说到事务日志,不得不说的就是redo和undo。
1.redo log
在innoDB的存储引擎中,事务日志通过重做(redo)日志和innoDB存储引擎的日志缓冲(InnoDB Log Buffer)实现。事务开启时,事务中的操作,都会先写入存储引擎的日志缓冲中,在事务提交之前,这些缓冲的日志都需要提前刷新到磁盘上持久化,这就是DBA们口中常说的“日志先行”(Write-Ahead Logging)。当事务提交之后,在Buffer Pool中映射的数据文件才会慢慢刷新到磁盘。此时如果数据库崩溃或者宕机,那么当系统重启进行恢复时,就可以根据redo log中记录的日志,把数据库恢复到崩溃前的一个状态。未完成的事务,可以继续提交,也可以选择回滚,这基于恢复的策略而定。
在系统启动的时候,就已经为redo log分配了一块连续的存储空间,以顺序追加的方式记录Redo Log,通过顺序IO来改善性能。所有的事务共享redo log的存储空间,它们的Redo Log按语句的执行顺序,依次交替的记录在一起。如下一个简单示例:
记录1:
记录2:
记录3:
记录4:
记录5:
2.undo log
undo log主要为事务的回滚服务。在事务执行的过程中,除了记录redo log,还会记录一定量的undo log。undo log记录了数据在每个操作前的状态,如果事务执行过程中需要回滚,就可以根据undo log进行回滚操作。单个事务的回滚,只会回滚当前事务做的操作,并不会影响到其他的事务做的操作。
以下是undo+redo事务的简化过程
假设有2个数值,分别为A和B,值为1,2
1. start transaction;
2. 记录 A=1 到undo log;
3. update A = 3;
4. 记录 A=3 到redo log;
5. 记录 B=2 到undo log;
6. update B = 4;
7. 记录B = 4 到redo log;
8. 将redo log刷新到磁盘
9. commit
在1-8的任意一步系统宕机,事务未提交,该事务就不会对磁盘上的数据做任何影响。如果在8-9之间宕机,恢复之后可以选择回滚,也可以选择继续完成事务提交,因为此时redo log已经持久化。若在9之后系统宕机,内存映射中变更的数据还来不及刷回磁盘,那么系统恢复之后,可以根据redo log把数据刷回磁盘。
所以,redo log其实保障的是事务的持久性和一致性,而undo log则保障了事务的原子性。
Mysql中的事务使用
MySQL的服务层不管理事务,而是由下层的存储引擎实现。比如InnoDB。
MySQL支持本地事务的语句:
START TRANSACTION | BEGIN [WORK] COMMIT [WORK] [AND [NO] CHAIN] [[NO] RELEASE] ROLLBACK [WORK] [AND [NO] CHAIN] [[NO] RELEASE] SET AUTOCOMMIT = {0 | 1}
事务使用注意点:
自动提交(autocommit):
Mysql默认采用自动提交模式,可以通过设置autocommit变量来启用或禁用自动提交模式
InnoDB在事务执行过程中,使用两阶段锁协议:
随时都可以执行锁定,InnoDB会根据隔离级别在需要的时候自动加锁;
锁只有在执行commit或者rollback的时候才会释放,并且所有的锁都是在同一时刻被释放。
InnoDB也支持通过特定的语句进行显示锁定(存储引擎层):
select ... lock in share mode //共享锁 select ... for update //排他锁
MySQL Server层的显示锁定:
lock table和unlock table
(更多阅读:MySQL锁总结)
MySQL对分布式事务的支持
分布式事务的实现方式有很多,既可以采用innoDB提供的原生的事务支持,也可以采用消息队列来实现分布式事务的最终一致性。这里我们主要聊一下innoDB对分布式事务的支持。
MySQL 从 5.0.3 开始支持分布式事务,当前分布式事务只支持 InnoDB 存储引擎。一个分布式事务会涉及多个行动,这些行动本身是事务性的。所有行动都必须一起成功完成,或者一起被回滚。
如图,mysql的分布式事务模型。模型中分三块:应用程序(AP)、资源管理器(RM)、事务管理器(TM):
分布式事务采用两段式提交(two-phase commit)的方式:
分布式事务(XA 事务)的 SQL 语法主要包括:
XA {START|BEGIN} xid [JOIN|RESUME]
虽然 MySQL 支持分布式事务,但是在测试过程中,还是发现存在一些问题:
如果分支事务在达到 prepare 状态时,数据库异常重新启动,服务器重新启动以后,可以继续对分支事务进行提交或者回滚得操作,但是提交的事务没有写 binlog,存在一定的隐患,可能导致使用 binlog 恢复丢失部分数据。如果存在复制的数据库,则有可能导致主从数据库的数据不一致。
如果分支事务在执行到 prepare 状态时,数据库异常,且不能再正常启动,需要使用备份和 binlog 来恢复数据,那么那些在 prepare 状态的分支事务因为并没有记录到 binlog,所以不能通过 binlog 进行恢复,在数据库恢复后,将丢失这部分的数据。
如果分支事务的客户端连接异常中止,那么数据库会自动回滚未完成的分支事务,如果此时分支事务已经执行到 prepare 状态, 那么这个分布式事务的其他分支可能已经成功提交,如果这个分支回滚,可能导致分布式事务的不完整,丢失部分分支事务的内容。
总之, MySQL 的分布式事务还存在比较严重的缺陷, 在数据库或者应用异常的情况下,
可能会导致分布式事务的不完整。如果应用对于数据的完整性要求不是很高,则可以考虑使
用。如果应用对事务的完整性有比较高的要求,那么对于当前的版本,则不推荐使用分布式
事务。
以上がデータベーストランザクションとMySQLトランザクションの概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。