sql >> Databáze >  >> RDS >> Sqlserver

Zařazení SQL Serveru do distribuované transakce XA

Jak získat přístup k SQL Serveru v kontextu transakce XA pomocí ovladače Easysoft SQL Server ODBC a Oracle Tuxedo.

Úvod

Proč jsou potřeba distribuované transakce

Transakce je série akcí prováděných jako jediná operace, ve které jsou buď provedeny všechny akce, nebo žádná. Transakce končí akcí potvrzení, díky níž jsou změny trvalé. Pokud některou ze změn nelze potvrdit, transakce se vrátí zpět a všechny změny se zruší.

Distribuovaná transakce je transakce, která může zahrnovat více zdrojů. Například jedna nebo více databází nebo databáze a fronta zpráv. Aby byla transakce úspěšně potvrzena, musí být úspěšně potvrzeny všechny jednotlivé zdroje; pokud je některý z nich neúspěšný, transakce se musí vrátit zpět ve všech zdrojích. Distribuovaná transakce může například sestávat z převodu peněz mezi dvěma bankovními účty, které provozují různé banky, a tak také v různých databázích. Nechtěli byste, aby byla žádná transakce potvrzena bez záruky, že obě budou úspěšně dokončeny. V opačném případě může dojít k duplikaci dat (pokud se vložení dokončí a odstranění se nezdaří) nebo ke ztrátě (pokud se mazání dokončí a vložení se nezdaří).

Kdykoli aplikace potřebuje přistupovat nebo aktualizovat data ve více transakčních zdrojích, měla by proto použít distribuovanou transakci. Je možné použít samostatnou transakci pro každý ze zdrojů, ale tento přístup je náchylný k chybám. Pokud se transakce v jednom zdroji úspěšně potvrdí, ale jiný selže a musí se vrátit zpět, první transakci již nelze vrátit zpět, takže stav aplikace bude nekonzistentní. Pokud se jeden zdroj úspěšně odevzdá, ale systém se zhroutí dříve, než se druhý zdroj podaří úspěšně odevzdat, aplikace je opět nekonzistentní.

XA

Model X/Open Distributed Transaction Processing (DTP) definuje architekturu pro zpracování distribuovaných transakcí. V architektuře DTP koordinující transakční manažer říká každému zdroji, jak zpracovat transakci, na základě své znalosti všech zdrojů účastnících se transakce. Prostředky, které běžně spravují vlastní potvrzení a obnovu transakcí, delegují tento úkol na správce transakcí.

Specifikace XA architektury poskytuje otevřený standard, který zajišťuje interoperabilitu napříč vyhovujícím transakčním middlewarem a databázovými produkty. Tyto různé zdroje se proto mohou společně účastnit distribuované transakce.

Model DTP obsahuje tři vzájemně související komponenty:

  • Aplikační program, který definuje hranice transakcí a specifikuje akce tvořící transakci.
  • Správci zdrojů, jako jsou databáze nebo systémy souborů, které poskytují přístup ke sdíleným zdrojům.
  • Správce transakcí, který transakcím přiděluje identifikátory, sleduje jejich průběh a přebírá odpovědnost za dokončení transakce a obnovu po selhání.

Standard XA definuje dvoufázový protokol potvrzování a rozhraní používané pro komunikaci mezi správcem transakcí a správcem prostředků. Dvoufázový protokol odevzdání poskytuje záruku typu vše nebo nic, že ​​všichni účastníci zapojení do transakce buď zadají, nebo se společně vrátí zpět. Proto se celá transakce potvrdí nebo se celá transakce vrátí zpět.

Dvoufázové potvrzení se skládá z fáze přípravy a fáze potvrzení. Během přípravné fáze musí všichni účastníci transakce souhlasit s provedením změn požadovaných transakcí. Pokud některý z účastníků nahlásí problém, přípravná fáze selže a transakce se vrátí zpět. Pokud je přípravná fáze úspěšná, fáze dvě, začíná fáze odevzdání. Během fáze potvrzení dá správce transakcí pokyn všem účastníkům, aby transakci potvrdili.

SQL Server a XA

Chcete-li povolit podporu XA v SQL Server 2019, postupujte podle pokynů v části „Spuštění služby MS DTC“ obsažené v tomto dokumentu:

Porozumění transakcím XA

Chcete-li povolit podporu XA v dřívějších verzích SQL Server, postupujte podle pokynů v tomto dokumentu:

Konfigurace transakcí XA v Microsoft SQL Server pro IBM Business Process Manager (BPM)

Ovladač SQL Server ODBC byl testován s instancemi SQL Server 2016 a 2019 s podporou XA.

Ovladač ODBC pro Easysoft SQL Server

Do ovladače SQL Server ODBC ve verzi 1.11.3 byla přidána podpora XA. Podpora XA ovladače byla testována s Oracle Tuxedo a SQL Server 2016 a 2019.

Chcete-li zařadit ovladač SQL Server ODBC do transakce XA, musíte použít strukturu s názvem es_xa_context ve vaší aplikaci. es_xa_context se připojí ke zdroji dat ODBC, který jste zadali v konfiguraci správce prostředků XA, a vrátí popisovač připojení. Například:

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

V Tuxedo, zdroj dat ODBC, který es_xa_context connects to je specifikováno ve Správci prostředků OPENINFO řetězec v konfiguračním souboru Tuxedo. V tomto příkladu je to "SQLSERVER_SAMPLE":

OPENINFO="EASYSOFT_SQLSERVER_ODBC:DSN=SQLSERVER_SAMPLE"

Název správce prostředků XA a přepínač XA definovaný ovladačem jsou EASYSOFT_SQLSERVER_ODBC a essql_xaosw .

Ve Tuxedu je zadáte v definičním souboru Tuxedo Resource Manager, ${TUXDIR}/udataobj/RM . Například:

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

Ukázka aplikace Easysoft / Tuxedo / SQL Server XA

Nejprve nastavte zdroj dat ovladače SQL Server ODBC, který se připojuje k instanci serveru SQL Server s podporou XA:

  1. Na vašem počítači Tuxedo nainstalujte ovladač SQL Server ODBC.
  2. Vytvořte zdroj dat ovladače SQL Server ODBC v odbc.ini. Například:
    [SQLSERVER_SAMPLE]
    Driver=Easysoft ODBC-SQL Server
    Description=Easysoft SQL Server ODBC driver
    Server=mymachine\myxaenabledinstance
    User=mydomain\myuser
    Password=mypassword
    Database=XA1
  3. Vytvořte vzorovou tabulku pro aplikaci Tuxedo:
    $ /usr/local/easysoft/unixODBC/bin/isql.sh -v SQLSERVER_SAMPLE
    SQL> CREATE TABLE [dbo].[tx_test1]([i] [int] NULL,[c] [varchar](100) NULL)

Vytvořte a spusťte ukázkovou aplikaci Tuxedo XA.

  1. $ cd ~
    $ mkdir simpdir
    $ cd simpdir
    $ touch simpcl.c simpserv.c ubbsimple
  2. Přidejte do simpcl.c tyto řádky:
    #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. Přidejte tyto řádky do 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. Přidejte do ubbsimple tyto řádky:
    *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. Nastavte své prostředí:
    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. Sestavte ukázkového klienta:
    buildclient -o simpcl -f simpcl.c

    Pokud se při sestavování klienta zobrazí chyba „nedefinovaný odkaz na dlopen“, zkuste místo toho tento příkaz:

    buildclient -o simpcl -f "-Xlinker --no-as-needed simpcl.c"
  7. Sestavte ukázkový server:
    buildserver -r EASYSOFT_SQLSERVER_ODBC -s EXECUTE -o simpserv -f "simpserv.c \
    -L/usr/local/easysoft/sqlserver/lib -lessqlsrv -lodbc"
  8. Vytvořte soubor TUXCONFIG pro ukázkovou aplikaci:
    tmloadcf ubbsimple
  9. Vytvořte protokolovací zařízení Tuxedo pro ukázkovou aplikaci:
    $ tmadmin -c
    > crdl -z /home/myuser/simpdir/tuxlog -b 512
  10. Sestavte správce transakcí Tuxedo, který je propojen s ovladačem SQL Server ODBC:
    $ buildtms -o mySQLSERVER_TMS -r EASYSOFT_SQLSERVER_ODBC
  11. Spusťte ukázkový server:
    $ tmboot
  12. Otestujte ukázkovou aplikaci:
    ./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. Pokud data vidíte v tabulce SQL Server, vypněte ukázkový server:
    tmshutdown

    Jinak se podívejte na ULOG.nnn v adresáři ukázkové aplikace.


  1. JDBC ResultSet získat sloupce s aliasem tabulky

  2. SQLcl pro přenos dat z Oracle do PostgreSQL nebo YugabyteDB 🅾🐘🚀

  3. více dotazů stejná tabulka, ale v různých sloupcích mysql

  4. Zařízení pro obnovu s nulovou ztrátou dat