sql >> データベース >  >> RDS >> Sqlserver

分散XAトランザクションへのSQLServerの参加

    Easysoft SQLServerODBCドライバーとOracleTuxedoを使用してXAトランザクションのコンテキストでSQLServerにアクセスする方法。

    はじめに

    分散トランザクションが必要な理由

    トランザクションは、すべてのアクションが実行されるか、実行されない単一の操作として実行される一連のアクションです。トランザクションは、変更を永続的にするコミットアクションで終了します。いずれかの変更をコミットできない場合、トランザクションはロールバックされ、すべての変更が元に戻されます。

    分散トランザクションは、複数のリソースにまたがる可能性のあるトランザクションです。たとえば、1つ以上のデータベースまたはデータベースとメッセージキュー。トランザクションが正常にコミットするには、すべての個々のリソースが正常にコミットする必要があります。それらのいずれかが失敗した場合、トランザクションはすべてのリソースでロールバックする必要があります。たとえば、分散トランザクションは、異なる銀行によってホストされている2つの銀行口座間の送金で構成されている場合があります。両方が正常に完了するという保証なしに、どちらかのトランザクションをコミットすることは望ましくありません。そうしないと、データが複製されたり(挿入が完了して削除が失敗した場合)、失われたり(削除が完了して挿入が失敗した場合)になる可能性があります。

    したがって、アプリケーションが複数のトランザクションリソースのデータにアクセスまたは更新する必要がある場合は常に、分散トランザクションを使用する必要があります。リソースごとに個別のトランザクションを使用することは可能ですが、このアプローチではエラーが発生しやすくなります。あるリソースのトランザクションが正常にコミットされ、別のリソースが失敗してロールバックする必要がある場合、最初のトランザクションはロールバックできなくなるため、アプリケーションの状態に一貫性がなくなります。一方のリソースが正常にコミットしたが、もう一方のリソースが正常にコミットする前にシステムがクラッシュした場合、アプリケーションは再び不整合になります。

    XA

    X / Open分散トランザクション処理(DTP)モデルは、分散トランザクション処理のアーキテクチャを定義します。 DTPアーキテクチャでは、調整トランザクションマネージャは、トランザクションに参加しているすべてのリソースに関する知識に基づいて、トランザクションの処理方法を各リソースに指示します。通常、独自のトランザクションコミットとリカバリを管理するリソースは、このタスクをトランザクションマネージャーに委任します。

    アーキテクチャのXA仕様は、準拠したトランザクションミドルウェアとデータベース製品間の相互運用性を保証するオープンスタンダードを提供します。したがって、これらのさまざまなリソースは、分散トランザクションに一緒に参加できます。

    DTPモデルには、相互に関連する3つのコンポーネントが含まれています。

    • トランザクションの境界を定義し、トランザクションを構成するアクションを指定するアプリケーションプログラム。
    • 共有リソースへのアクセスを提供するデータベースやファイルシステムなどのリソースマネージャー。
    • トランザクションに識別子を割り当て、その進行状況を監視し、トランザクションの完了と障害の回復に責任を持つトランザクションマネージャー。

    XA標準は、2フェーズコミットプロトコルと、トランザクションマネージャーとリソースマネージャー間の通信に使用されるインターフェイスを定義します。 2フェーズコミットプロトコルは、トランザクションに関与するすべての参加者が一緒にコミットまたはロールバックすることを保証します。したがって、トランザクション全体がコミットされるか、トランザクション全体がロールバックされます。

    2フェーズコミットは、準備フェーズとコミットフェーズで構成されます。準備フェーズでは、トランザクションのすべての参加者が、トランザクションに必要な変更を完了することに同意する必要があります。参加者のいずれかが問題を報告した場合、準備フェーズは失敗し、トランザクションはロールバックされます。準備フェーズが成功すると、フェーズ2、コミットフェーズが開始されます。コミットフェーズ中に、トランザクションマネージャーはすべての参加者にトランザクションをコミットするように指示します。

    SQLServerとXA

    SQL Server 2019でXAサポートを有効にするには、このドキュメントに含まれている「MSDTCサービスの実行」セクションの手順に従ってください。

    XAトランザクションを理解する

    以前のバージョンのSQLServerでXAサポートを有効にするには、次のドキュメントの手順に従ってください。

    IBM Business Process Manager(BPM)用のMicrosoftSQLServerでのXAトランザクションの構成

    SQL Server ODBCドライバーは、XA対応のSQLServer2016および2019インスタンスでテストされています。

    Easysoft SQLServerODBCドライバー

    XAサポートは、バージョン1.11.3でSQLServerODBCドライバーに追加されました。ドライバのXAサポートは、OracleTuxedoおよびSQLServer2016および2019でテストされています。

    SQL Server ODBCドライバーをXAトランザクションに参加させるには、es_xa_contextという名前の構造体を使用する必要があります。 アプリケーションで。 es_xa_context XAリソースマネージャー構成で指定したODBCデータソースに接続し、接続ハンドルを返します。例:

    int ret;
    SQLHANDLE hEnv, hConn;
    ret = es_xa_context( NULL, &hEnv, &hConn );

    タキシードでは、es_xa_contextであるODBCデータソース 接続先は、リソースマネージャーのOPENINFOで指定されます そんなTuxedo設定ファイルの文字列。この例では、「SQLSERVER_SAMPLE」です:

    OPENINFO="EASYSOFT_SQLSERVER_ODBC:DSN=SQLSERVER_SAMPLE"

    ドライバー定義のXAリソースマネージャー名とXAスイッチはEASYSOFT_SQLSERVER_ODBCです。 およびessql_xaosw

    そんなTuxedoでは、TuxedoResourceManager定義ファイル${TUXDIR}/udataobj/RMでこれらを指定します。 。例:

    EASYSOFT_SQLSERVER_ODBC:essql_xaosw:-L/usr/local/easysoft/sqlserver/lib -lessqlsrv -lodbcinst

    サンプルEasysoft/Tuxedo / SQLServerXAアプリケーション

    まず、XA対応のSQLServerインスタンスに接続するSQLServerODBCドライバーデータソースを設定します。

    1. あなたのTuxedoマシンに、SQLServerODBCドライバーをインストールします。
    2. odbc.iniにSQLServerODBCドライバーデータソースを作成します。例:
      [SQLSERVER_SAMPLE]
      Driver=Easysoft ODBC-SQL Server
      Description=Easysoft SQL Server ODBC driver
      Server=mymachine\myxaenabledinstance
      User=mydomain\myuser
      Password=mypassword
      Database=XA1
    3. Tuxedoアプリケーションのサンプルテーブルを作成します。
      $ /usr/local/easysoft/unixODBC/bin/isql.sh -v SQLSERVER_SAMPLE
      SQL> CREATE TABLE [dbo].[tx_test1]([i] [int] NULL,[c] [varchar](100) NULL)

    サンプルのTuxedoXAアプリケーションを作成して実行します。

    1. $ cd ~
      $ mkdir simpdir
      $ cd simpdir
      $ touch simpcl.c simpserv.c ubbsimple
    2. 次の行をsimpcl.cに追加します。
      #include <stdio.h>
      #include "atmi.h"               /* TUXEDO  Header File */
      
      
      #if defined(__STDC__) || defined(__cplusplus)
      main(int argc, char *argv[])
      #else
      main(argc, argv)
      int argc;
      char *argv[];
      #endif
      
      {
      
              char *sendbuf, *rcvbuf;
              long sendlen, rcvlen;
              int ret;
      
              if(argc != 2) {
                      (void) fprintf(stderr, "Usage: simpcl <SQL>\n");
                      exit(1);
              }
      
              /* Attach to System/T as a Client Process */
              if (tpinit((TPINIT *) NULL) == -1) {
                      (void) fprintf(stderr, "Tpinit failed\n");
                      exit(1);
              }
      
              sendlen = strlen(argv[1]);
      
              /* Allocate STRING buffers for the request and the reply */
      
              if((sendbuf = (char *) tpalloc("STRING", NULL, sendlen+1)) == NULL) {
                      (void) fprintf(stderr,"Error allocating send buffer\n");
                      tpterm();
                      exit(1);
              }
      
              if((rcvbuf = (char *) tpalloc("STRING", NULL, sendlen+1)) == NULL) {
                      (void) fprintf(stderr,"Error allocating receive buffer\n");
                      tpfree(sendbuf);
                      tpterm();
                      exit(1);
              }
      
              (void) strcpy(sendbuf, argv[1]);
      
              /* Request the service EXECUTE, waiting for a reply */
              ret = tpcall("EXECUTE", (char *)sendbuf, 0, (char **)&rcvbuf, &rcvlen, (long)0);
      
              if(ret == -1) {
                      (void) fprintf(stderr, "Can't send request to service EXECUTE\n");
                      (void) fprintf(stderr, "Tperrno = %d\n", tperrno);
                      tpfree(sendbuf);
                      tpfree(rcvbuf);
                      tpterm();
                      exit(1);
              }
      
              (void) fprintf(stdout, "Returned string is: %s\n", rcvbuf);
      
              /* Free Buffers & Detach from System/T */
              tpfree(sendbuf);
              tpfree(rcvbuf);
              tpterm();
              return(0);
      }
    3. 次の行をsimpserv.cに追加します。
      #include <stdio.h>
      #include <ctype.h>
      #include <atmi.h>       /* TUXEDO Header File */
      #include <userlog.h>    /* TUXEDO Header File */
      #include <xa.h>
      #include <sql.h>
      #include <sqlext.h>
      #include <string.h>
      
      
      /* tpsvrinit is executed when a server is booted, before it begins
         processing requests.  It is not necessary to have this function.
         Also available is tpsvrdone (not used in this example), which is
         called at server shutdown time.
      */
      
      
      int tpsvrinit(int argc, char *argv[])
      {
              int ret;
      
              /* Some compilers warn if argc and argv aren't used. */
              argc = argc;
              argv = argv;
      
              /* simpapp is non-transactional, so there is no need for tpsvrinit()
                 to call tx_open() or tpopen().  However, if this code is modified
                 to run in a Tuxedo group associated with a Resource Manager then
                 either a call to tx_open() or a call to tpopen() must be inserted
                 here.
              */
      
              /* userlog writes to the central TUXEDO message log */
              userlog("Welcome to the simple server");
      
              ret = tpopen();
      
              userlog("tpopen returned %d, error=%x", ret, tperrno );
      
              return(0);
      }
      
      void tpsvrdone( void )
      {
              int ret;
      
              ret = tpclose();
      
              userlog("tpclose returned %d", ret);
      }
      
      /* This function performs the actual service requested by the client.
         Its argument is a structure containing among other things a pointer
         to the data buffer, and the length of the data buffer.
      */
      
      xa_open_entry() call.
      int es_xa_context( int* rmid, SQLHANDLE* henv, SQLHANDLE* hdbc );
      
      void EXECUTE(TPSVCINFO *rqst)
      {
              int ret;
              char *result;
              SQLHANDLE hStmt;
              char str[ 256 ];
              SQLHANDLE hEnv, hConn;
              SQLSMALLINT slen;
      
              ret = es_xa_context( NULL, &hEnv, &hConn );
      
              userlog("es_xa_context returns %d, hEnv = %p, hConn = %p", ret, hEnv, hConn );
      
              if ( ret != 0 ) {
                      result = tpalloc( "STRING", "*", 128 );
                      sprintf( result, "es_xa_context returned %d", ret );
      
                      /* Return the transformed buffer to the requestor. */
                      tpreturn(TPSUCCESS, 0, result, strlen( result ), 0);
              }
              else {
      
                      ret = tpbegin( 0, 0 );
      
                      ret = SQLAllocHandle( SQL_HANDLE_STMT, hConn, &hStmt );
      
                      ret = SQLExecDirect( hStmt, rqst -> data, rqst -> len );
      
                      ret = SQLFreeHandle( SQL_HANDLE_STMT, hStmt );
      
                      ret = tpcommit( 0 );
      
                      result = tpalloc( "STRING", "*", 128 );
                      sprintf( result, "tpcommit returns %d", ret );
      
                      /* Return the transformed buffer to the requestor. */
                      tpreturn(TPSUCCESS, 0, result, strlen( result ), 0);
              }
      }
    4. 次の行をubbsimpleに追加します。
      *RESOURCES
      IPCKEY          123456
      
      DOMAINID        simpapp
      MASTER          simple
      MAXACCESSERS    20
      MAXSERVERS      10
      MAXSERVICES     10
      MODEL           SHM
      LDBAL           N
      
      *MACHINES
      DEFAULT:
                      APPDIR="/home/myuser/simpdir"
                      TUXCONFIG="/home/myuser/simpdir/tuxconfig"
                      TUXDIR="/home/myuser/OraHome/tuxedo12.2.2.0.0"
      
      mymachine         LMID=simple
      
      TLOGNAME=TLOG
      TLOGDEVICE="/home/myuser/simpdir/tuxlog"
      
      
      *GROUPS
      GROUP1
              LMID=simple     GRPNO=1 OPENINFO=NONE
              TMSNAME=mySQLSERVER_TMS
              OPENINFO="EASYSOFT_SQLSERVER_ODBC:DSN=SQLSERVER_SAMPLE"
      
      *SERVERS
      DEFAULT:
                      CLOPT="-A"
      
      simpserv        SRVGRP=GROUP1 SRVID=1
      
      *SERVICES
      EXECUTE
    5. 環境を設定します:
      export TUXDIR=/home/myuser/OraHome/tuxedo12.2.2.0.0
      export TUXCONFIG=/home/myuser/simpdir/tuxconfig
      export PATH=$PATH:$TUXDIR/bin
      export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$TUXDIR/lib:/usr/local/easysoft/unixODBC/lib: \
      /usr/local/easysoft/sqlserver/lib:/usr/local/easysoft/lib
    6. サンプルクライアントをビルドします:
      buildclient -o simpcl -f simpcl.c

      クライアントのビルド中に「dlopenへの未定義の参照」というエラーが発生した場合は、代わりに次のコマンドを試してください。

      buildclient -o simpcl -f "-Xlinker --no-as-needed simpcl.c"
    7. サンプルサーバーをビルドします:
      buildserver -r EASYSOFT_SQLSERVER_ODBC -s EXECUTE -o simpserv -f "simpserv.c \
      -L/usr/local/easysoft/sqlserver/lib -lessqlsrv -lodbc"
    8. サンプルアプリケーションのTUXCONFIGファイルを作成します:
      tmloadcf ubbsimple
    9. サンプルアプリケーション用のTuxedoロギングデバイスを作成します:
      $ tmadmin -c
      > crdl -z /home/myuser/simpdir/tuxlog -b 512
    10. SQLServerODBCドライバーとインターフェイスするTuxedoトランザクションマネージャーを構築します。
      $ buildtms -o mySQLSERVER_TMS -r EASYSOFT_SQLSERVER_ODBC
    11. サンプルサーバーを起動します:
      $ tmboot
    12. サンプルアプリケーションをテストします:
      ./simpcl "insert into tx_test1 values( 1, 'hello world' )"
      /usr/local/easysoft/unixODBC/bin/isql.sh -v SQLSERVER_SAMPLE
      SQL> select * from tx_test1
      +------------+--------------+
      | i          | c            |                                                                                                   
      +------------+--------------+
      | 1          | hello world  |                                                                                         
      +------------+--------------+
    13. SQL Serverテーブルにデータが表示されている場合は、サンプルサーバーをシャットダウンします:
      tmshutdown

      それ以外の場合は、サンプルアプリケーションディレクトリのULOG.nnnを参照してください。


    1. Postgresqlの複数の列でWHEREINを実行する

    2. MySQL LOAD DATA INFILE with ON DUPLICATE KEY UPDATE

    3. getReadableDatabase()を呼び出すときのNullポインタ例外

    4. Oracleを使用してHibernateに最後に挿入された行のIDを取得できません