XAトランザクションの2.0 MySQLのサポート
2018年2月5日午前2時20分50秒4994 1
XAトランザクションを分散し、そして唯一のInnoDBストレージエンジンのサポートをサポートするために最初からのMySQL 5.0.3。XAの直接サポートの開始後からのMySQLのConnector / J 5.0.0バージョン。
これは、リソースマネージャ(RM)に属しDTPモデルでは、mysqlのことに留意すべきです。そして完全な分散トランザクションは、通常、トランザクションマネージャTMによって調整統一するために、複数のRMがあります。だから、ここで一般的に、XA分散トランザクションのMySQLのサポートだのMySQLの単一のインスタンスは、独自の事務ブランチを実行する方法を指します。
MySQLのXAトランザクションSQL構文
https://dev.mysql.com/doc/refman/5.7/en/xa-statements.html
- XA {START | BEGIN} XIDをXIDは、トランザクションブランチ識別子を表す一意の値であり、| | [RESUME登録しよう]あなたの代わりにXAのXA STARTを使用している場合は、[登録しようRESUME] //オープンXAトランザクションは、それがサポートしない、BEGIN
- // XAトランザクションを終了したXA ENDがxid [MIGRATE]を[サスペンド]、サポートしていません[SUSPEND [FOR MIGRATE]]
- XAを提出する準備ができてXID PREPARE
- XAは、XID [ONE PHASE] //提出し、あなたはONE PHASEを使用している場合、それは1フェーズ・コミット使用して意味をCOMMIT。唯一のRMが関与場合、2つのフェーズは、コミットプロトコル1フェーズ・コミットのために、それを最適化することができます
- XA ROLLBACK XID //ロールバック
- XAは、準備フェーズに[CONVERT XID] //リストのすべてのXAトランザクションを回復します
ここでmsyql XAトランザクションの簡単なケースであり、トランザクションは、グローバル・トランザクションのブランチとしてMySQLを示し、行がテーブルに挿入され
- MySQLの> XA START 'xatest'; // 'xatest' はXIDの値です
- クエリOK、影響を受けた0行(0.00秒)
- ユーザーへのMySQLの>の挿入(名)の値( "tianshozuhi");
- クエリOK、影響を受けた1行(0.00秒)
- MySQLの> XA END 'xatest';
- クエリOK、影響を受けた0行(0.00秒)
- MySQLの> XA PREPARE 'xatest';
- クエリOK、影響を受けた0行(0.01秒)
- MySQLの> XAは 'xatest' COMMIT;
- クエリOK、影響を受けた0行(0.01秒)
MySQLのXAトランザクションの状態
https://dev.mysql.com/doc/refman/5.7/en/xa-states.html
XAトランザクションの状態は、以下のステップが展開されます
1. XA START XAトランザクションを開始し、それを配置するACTIVE
状態。
2. ACTIVE XAトランザクションの状態については、我々はXA ENDステートメントを発行し、その後、問題を構成するSQL文を実行することができます。XA ENDはトランザクションを置きIDLE
状態。
3.状態IDLEのXAトランザクションのために、あなたはXAは、ステートメントまたはXAがCOMMIT PREPARE ... ONE PHASEステートメントを実行することができます。
-
XAは中プットにトランザクションをPREPARE
PREPARED
状態。XAは、XAはPREPARED状態でリストにすべてのXAトランザクションを回復するので、その出力にトランザクションのxid値を含みます。この時点で声明を回復します。 -
XAは、COMMIT ... ONE PHASEをトランザクションの準備と提出のために。XID値は、トランザクションが終了するので、XAは、RECOVER表示されません。
4. PREPARED XAトランザクションの状態について、あなたはXAコミットし、トランザクションを終了、またはロールバックにXA ROLLBACKを解放し、トランザクションを終了するCOMMIT文を発行することができます。
関係する特定のクライアント接続の場合は、XAトランザクションと非XAトランザクション(ある、ローカルトランザクション)は、相互に排他的です。XAトランザクションがコミットまたはロールバックされるまで例えば、それはXAトランザクションを開くには、「XA START」コマンドを行っていた、ローカルトランザクションを開始することはできません。ローカルトランザクションがSTARTのTRANSACTIONを使用して開始している場合は、トランザクションがコミットまたはロールバックされるまで、逆に、XAステートメントは使用できません。
XAトランザクションがACTIVE状態で、直接提出することができないならば、あなたがしなければ最終的に、MySQLは例外がスローされます。
- ERROR 1399(XAE07):XAER_RMFAIL:コマンドが実行できません
- グローバルトランザクションがACTIVE状態にあるとき、
XIDの3説明
MySQLはトランザクションブランチの識別子として使用XID。実際XIDトランザクションブランチ識別子をXA仕様、<<分散トランザクション処理に定義される通りである:XA仕様>>セクション4.2、所定の構造をXID次のように、C言語で記述されます。
- / *
- *トランザクションブランチの識別:XIDとNULLXID:
- * /
- #define XIDDATASIZEバイトで128 / *サイズ* /
- GTRIDのバイト単位の#define MAXGTRIDSIZE 64 / *最大サイズ* /
- #define MAXBQUALSIZEのbqualのバイト64 / *最大サイズ* /
- 構造体xid_t {
- 長期のformatID; / *フォーマット識別子* /
- 長いgtrid_length; / *値1-64 * /
- 長いbqual_length; / *値1-64 * /
- CHARデータ[XIDDATASIZE]。
- }。
- / *
- * -1のformatIDの値はXIDがnullであることを意味します。
- * /
- typedefは構造体xid_t XID。
- / *
- * RMSは翻訳メモリを呼び出したことにより、ルーチンの宣言:
- * /
- extern int型のax_reg関数(long int型、XID *、);
- extern int型ax_unregが入っ(int型、長いです)。
XA仕様では、XIDは、4つの成分を有する定義されています。
GTRID:
グローバルトランザクション識別子(グローバルトランザクション識別子)は、64バイトの最大値を超えることはできません
bqualが:
分岐修飾子(分岐修飾子)、64バイトの最大値を超えることはできません
データ:
内容のbqual gtridとスプライシングされxid値、。bqual GTRIDと最大64バイト、データ128の最大長さであるからです。しかし、XIDの構造では、何のはgtridとbqual、唯一gtrid_length、bqual_lengthはありません。両方の内容をデータに保存されているので、我々は、データへのアンチはgtridとbqual応じて起動することができますので。例えば、 "g12345"(5バイト)としてGTRID、 "B456"(4バイト)としてのbqual。XIDは、次に構造を構築、gtrid_length = 5、bqual_length = 4、データ= "g12345b456"、次いで逆推力の場合:
データ[0] GTRID [gtrid_length-1]セクションとの間のデータの値であるから、データから[gtrid_length]データ[gtrid_lengthのbqual_length-1 +]のbqualの値の一部です。
formatID:
memcachedの中や録画機能は、フラグフィールドの役割に類似のformatIDのGTRID、のbqual形式にあります。XA大会の構造がxidの一部によって仕様が、保存されたGTRIDデータ、コンテンツが最後にする必要がありますどのような形式のbqualを必要としません。あなたは、開発者の裁量限り、コンテンツデータの究極の保証はグローバルに一意であることができるものを選択し、最後に、あなたはまた、文字列を使用するように選択することができ、番号を使用することができます。XA仕様では、ケースのformatIDを0に設定すべき内容XIDを、整理するOSI CCRのスタイルを使用することを推奨しています。
MySQLの公式ドキュメントでは、XIDの組成物は、同様の説明があります。
- XID:GTRID [、のbqual [、のformatID]]
これは、のbqual、のformatIDはオプションです。次のように説明しました:
GTRID:グローバル・トランザクション識別子(グローバルトランザクション識別子)があり、
bqual:修飾子は枝(ブランチ修飾子)は、無のbqual場合、デフォルトは「空の文字列」です。
formatID:数であり、最小値は0である符号なし整数(符号なし整数)であるGTRIDのbqual値をマーキングするためのフォーマット。ノーのformatID場合は、そのデフォルト値は1です。
特に注目すべきなのはつまり、トランザクションブランチ識別子としてXIDは、理論的には、長いその上にブランチ修飾子(bqual)で構成さなどとして、なぜグローバル・トランザクション識別子(GTRID)が含まれている必要がありますか?これは、管理の便宜のために主に、XIDに含むことによって、我々は簡単にグローバル・トランザクションは、トランザクションのブランチに属するかを決定することができます。
前述のXAは、コマンドの役割は、すべてのXAトランザクションが準備フェーズにある一覧にあるRECOVERたとえば、次のようにケースです。
- MySQLの> XA RECOVER。
- + ---------- + -------------- + -------------- + -------- ------ +
- | formatID | gtrid_length | bqual_length | データ|
- + ---------- + -------------- + -------------- + -------- ------ +
- | 1 | 6 | 6 | g12345b67890 |
- + ---------- + -------------- + -------------- + -------- ------ +
ここに記載されている情報は、以前の報告によると、我々はそれを推測することができ、トランザクションxidの枝で構成されています。
GTRIDデータは[gtrid_length-1]セクションの、データ内容〔= 5 6-1]セクションに、すなわち、データ[0]、結果はg12345 [0]コンテンツデータです。
bqualが、データコンテンツ部分の[gtrid_length + bqual_length-1]、即ち、データにデータ[gtrid_length] [6]コンテンツデータ[6 + 6-1 = 11]部分、結果b67890です。
したがって、この情報に基づいて、我々はXIDを決定することができ表される:グローバル・トランザクション(g12345)トランザクションブランチに(b67890)。
JDBCのMySQL XA総務を通じて操作する4、
以降のバージョン5.0.0からのMySQLのConnector / Jは、XAインタフェースのJavaのバージョンを達成するために提供されるXA、直接サポートの提供を開始しました。私たちは、直接mysqlのXAトランザクションのJavaコードを実行できることを意味します。
コードの製造における事業開発スタッフは、直接これらのインタフェースにXAトランザクション・オペレーションを操作することはできませんことに留意すべきです。オープンエンド、準備、コミット、ロールバックなどの操作上のDTPモデル、RMトランザクション・ブランチなので、トランザクション・マネージャー(TM)統合管理でなければなりません。
我々はまだTMと接触していないので、我々は、あなたの脳の知恵で、「人間の肉トランザクションマネージャ」への復帰を作るかもしれないmysqlのトランザクションブランチのXAの実装上の複数のインスタンスを制御するために、コミット/ロールバックを。これらのインタフェースを直接操作することで、あなたは、XA総務は、より深く理解します。
- 輸入com.mysql.jdbc.jdbc2.optional.MysqlXAConnection。
- 輸入com.mysql.jdbc.jdbc2.optional.MysqlXid;
- 輸入javax.sql.XAConnection。
- 輸入javax.transaction.xa.XAExceptionの。
- 輸入javax.transaction.xa.XAResourceの;
- 輸入javax.transaction.xa.Xid。
- インポートのjava.sql.Connection;
- インポートのjava.sql.DriverManager。
- インポートのjava.sql.PreparedStatement;
- 輸入ます。java.sql.SQLException;
- パブリッククラスMysqlXAConnectionTest {
- 公共の静的な無効メイン(文字列[]引数)はSQLExceptionが{スロー
- //真は、デバッグのためにその印刷,, XAステートメントを示し、
- ブールlogXaCommands =はtrue。
- //リソース管理インターフェイスインスタンスRM1の操作を取得します。
- 接続CONN1 =たDriverManager.getConnection( "JDBC:MySQLの:// localhostを:3306 /試験"、 "ルート"、 "shxx12151022")。
- するXAConnection xaConn1は新しいMysqlXAConnection((com.mysql.jdbc.Connection)CONN1、logXaCommands)を=。
- XAResourceのRM1 = xaConn1.getXAResource()。
- //リソース管理インターフェイスインスタンスRM2の操作を取得します。
- 接続conn2 =したDriverManager.getConnection( "JDBCます。mysql:// localhostを:3306 /テスト"、 "根"、
- "shxx12151022");
- するXAConnection xaConn2は新しいMysqlXAConnection((com.mysql.jdbc.Connection)conn2、logXaCommands)を=。
- XAResourceのRM2 = xaConn2.getXAResource()。
- // APは、分散トランザクション要求TMは、TMは、グローバルトランザクションIDを生成し、実行します
- バイト[] GTRID = "g12345" .getBytes()。
- int型のformatID = 1;
- {試します
- //ファイル名を指定して実行されたトランザクションブランチ==================== ============== RM1とRM2に
- トランザクションブランチ// TM生成RM1のID
- バイト[] bqual1 = "B00001" .getBytes()。
- xidのXID1 =新しいMysqlXid(GTRID、bqual1、のformatID)。
- // RM1上のトランザクションブランチを実行します
- rm1.start(XID1、XAResource.TMNOFLAGS); // TMNOFLAGS、TMJOIN、またはTMRESUMEの一つ。
- PreparedStatementのPS1 = conn1.prepareStatement( "ユーザにINSERT(名)VALUES( 'tianshouzhi')")。
- ps1.execute();
- rm1.end(XID1、XAResource.TMSUCCESS)。
- // TMはRM2上のトランザクション・ブランチIDを生成し、
- バイト[] bqual2 = "b00002" .getBytes()。
- xidのXID2 =新しいMysqlXid(GTRID、bqual2、のformatID)。
- // RM2上のトランザクションブランチを実行します
- rm2.start(XID2、XAResource.TMNOFLAGS)。
- PreparedStatementのPS2 = conn2.prepareStatement( "ユーザーへのINSERT(名)VALUES( 'wangxiaoxiao')");
- ps2.execute();
- rm2.end(XID2、XAResource.TMSUCCESS)。
- // =================== 2フェーズ・コミット========================== ======
- //フェーズ1:RMは、トランザクションブランチをコミットするすべての準備を頼みます
- INT rm1_prepare = rm1.prepare(XID1)。
- INT rm2_prepare = rm2.prepare(XID2)。
- //フェーズ2:すべてのトランザクション・ブランチをコミット
- ブールONEPHASE =偽; // TM分析トランザクションは二つの枝を持って、最適化は、ステージに提出することはできません
- もし(rm1_prepare == XAResource.XA_OK
- && rm2_prepare == XAResource.XA_OK
- ){//、すべてのトランザクションが成功したブランチです準備すべてのトランザクションブランチをコミット
- rm1.commit(XID1、ONEPHASE)。
- rm2.commit(XID2、ONEPHASE)。
- // {}誰成功したトランザクションブランチ、ロールバックが存在しない場合
- rm1.rollback(XID1)。
- rm1.rollback(XID2)。
- }
- }キャッチ(使ってXAException電子){
- //例外が発生した場合、だけでなく、ロールバック
- e.printStackTrace();
- }
- }
- }
この場合、我々は2つのRMの場合には分散ワークフロートランザクションを示しています。、RMのグローバル・トランザクションIDとブランチトランザクションIDを生成し、オープントランザクションブランチ:私たちのような、これの多くは動作するはずですので、TMの内容との契約は、直接上記のコードに反映扱い、「人事管理」TMとして働きので、 2フェーズコミットようにと。「人事管理」として私たち自身は、非常に信頼性があるが、上記のコードは、私たちはTM主要な内部のワークフローは以下のようであることを理解することができますが。
我々は通常、分散トランザクションを操作するときに、コードを大幅に簡略化することができ、第三者又はTM機能によって提供されるコンテナを使用するため、実際の開発では、コードは、表面上のような複雑なようではありません。
プログラムは、XAコマンドの実行をプリントアウトするために戻って実行されている場合最後に、我々は真のlogXaCommands =、からです。次のとおりです。
- 金2月2日夜06時09分29秒CST 2018 DEBUG:実行XA声明:XA START 0x673132333435,0x623030303031,0x1
- 金2月2日夜06時09分29秒CST 2018 DEBUG:実行XA声明:XA END 0x673132333435,0x623030303031,0x1
- 金2月2日夜06時09分29秒CST 2018 DEBUG:実行XA声明:XA START 0x673132333435,0x623030303032,0x1
- 金2月2日夜06時09分29秒CST 2018 DEBUG:実行XA声明:XA END 0x673132333435,0x623030303032,0x1
- 金2月2日夜06時09分29秒CST 2018 DEBUG:XA文を実行:XAは0x673132333435,0x623030303031,0x1をPREPARE
- 金2月2日夜06時09分29秒CST 2018 DEBUG:XA文を実行:XAは0x673132333435,0x623030303032,0x1をPREPARE
- 金2月2日夜06時09分29秒CST 2018 DEBUG:XA文を実行:XAは0x673132333435,0x623030303031,0x1をCOMMIT
- 金2月2日夜06時09分29秒CST 2018 DEBUG:XA文を実行:XAは0x673132333435,0x623030303032,0x1をCOMMIT
5 MySQLのConnector / JのXAトランザクションのサポート、単純なソースコード解析
最後に、我々は簡単な分析を行うために上記のソースコードを持っています。操作の前に直接mysqlコマンドを使用している場合、我々は、などXAコマンド「XA STARTがXID」XAトランザクションを行いました。上記のコードではjavaの後、我々はパッケージになっており、共通のリンク接続を取得しますMysqlXAConnection
。次のとおりです。
com.mysql.jdbc.jdbc2.optional.MysqlXAConnection
- パブリッククラスMysqlXAConnectionはMysqlPooledConnection器具れるXAConnection、XAResourceを{延び
- プライベートcom.mysql.jdbc.Connection underlyingConnection。
- プライベートログログ。
- 保護されたブールlogXaCommands。
- //コンストラクタ
- 公共MysqlXAConnection(com.mysql.jdbc.Connection接続、ブールlogXaCommands)はSQLExceptionが{スロー
- スーパー(接続)。
- this.underlyingConnection =接続;
- this.log = connection.getLog()。
- this.logXaCommands = logXaCommands。
- }
- ...
- }
あなたが見ることができ、MysqlXAConnection自体は実装XAResource
インターフェイスを、私たちgetXAResource()メソッド、独自ののリターンです
com.mysql.jdbc.jdbc2.optional.MysqlXAConnection#getXAResource
- 公共のXAResource getXAResource()SQLExceptionが{スロー
- これを返します。
- }
その後、我々は方法がXAResourceのXAトランザクションを開くために呼び出され始めます。次のようにソーススタート方法は次のとおりです。
com.mysql.jdbc.jdbc2.optional.MysqlXAConnection#開始
- 公共のボイド開始(XIDがxid、int型のフラグ)が使ってXAExceptionをスロー{
- // 1、パッケージXAコマンド
- StringBuilderのcommandBuf =新しいStringBuilderの(MAX_COMMAND_LENGTH)。
- commandBuf.append( "XA START");
- appendXid(commandBuf、XID)。
- // 2、フラグマーカーを追加
- スイッチ(フラグ){
- ケースTMJOIN:
- commandBuf.append( "結合")。
- ブレーク;
- ケースTMRESUME:
- commandBuf.append( "RESUME");
- ブレーク;
- ケースTMNOFLAGS:
- //今オン
- ブレーク;
- デフォルト:
- 新しい使ってXAException(XAException.XAER_INVAL)を投げます。
- }
- //ファイル名を指定して実行
- dispatchCommand(commandBuf.toString())。
- this.underlyingConnection.setInGlobalTx(真の);
- }
私たちは、「XA START XID [登録しよう| RESUME]」我々はMysqlXAConnection開始メソッドが実際に実装されて呼び出すことがわかります、それを指揮し、我々は直接コマンドラインから同じと同じですが、カプセル化することにより、私たちの業務を簡素化します。
エンドため、ロールバックMysqlXAConnection省略し、また類似している、のような、コミット準備。
最終的なメモは、MySQLコネクタ/ J XA上述したように、ユーザインタフェース、を提供するXAConnection、XAResourceの、のXid等は、JTA仕様に実際にJTA仕様は、次のセクションで説明する続きます。