sql >> Database >  >> RDS >> Sqlserver

SQL Server inschakelen in een gedistribueerde XA-transactie

Toegang krijgen tot SQL Server in de context van een XA-transactie met de Easysoft SQL Server ODBC-driver en Oracle Tuxedo.

Inleiding

Waarom gedistribueerde transacties nodig zijn

Een transactie is een reeks acties die worden uitgevoerd als een enkele bewerking waarbij ofwel alle acties worden uitgevoerd of geen ervan. Een transactie eindigt met een commit-actie die de wijzigingen permanent maakt. Als een van de wijzigingen niet kan worden doorgevoerd, wordt de transactie teruggedraaid en worden alle wijzigingen ongedaan gemaakt.

Een gedistribueerde transactie is een transactie die meerdere bronnen kan omvatten. Bijvoorbeeld een of meer databases of een database en een berichtenwachtrij. Om de transactie succesvol te laten plaatsvinden, moeten alle individuele resources succesvol worden vastgelegd; als een van deze niet succesvol is, moet de transactie in alle bronnen worden teruggedraaid. Een gedistribueerde transactie kan bijvoorbeeld bestaan ​​uit een geldoverdracht tussen twee bankrekeningen, gehost door verschillende banken, en dus ook op verschillende databases. U wilt niet dat een van beide transacties wordt uitgevoerd zonder de garantie dat beide met succes worden voltooid. Anders kunnen gegevens worden gedupliceerd (als het invoegen is voltooid en het verwijderen mislukt) of verloren gaan (als het verwijderen is voltooid en het invoegen mislukt).

Wanneer een toepassing daarom toegang moet krijgen tot de gegevens in meerdere transactiebronnen of deze moet bijwerken, moet deze een gedistribueerde transactie gebruiken. Het is mogelijk om voor elk van de resources een afzonderlijke transactie te gebruiken, maar deze aanpak is foutgevoelig. Als de transactie in de ene resource met succes wordt doorgevoerd, maar een andere mislukt en moet worden teruggedraaid, kan de eerste transactie niet meer worden teruggedraaid, waardoor de status van de toepassing inconsistent wordt. Als de ene bron met succes vastlegt, maar het systeem crasht voordat de andere bron met succes kan vastleggen, is de toepassing opnieuw inconsistent.

XA

Het X/Open Distributed Transaction Processing (DTP)-model definieert een architectuur voor gedistribueerde transactieverwerking. In de DTP-architectuur vertelt een coördinerende transactiemanager elke resource hoe een transactie moet worden verwerkt, op basis van zijn kennis van alle resources die aan de transactie deelnemen. Resources die normaal gesproken hun eigen transactie vastleggen en herstellen, delegeren deze taak aan de transactiemanager.

De XA-specificatie van de architectuur biedt een open standaard die zorgt voor interoperabiliteit tussen conforme transactionele middleware- en databaseproducten. Deze verschillende bronnen kunnen daarom samen deelnemen aan een gedistribueerde transactie.

Het DTP-model omvat drie onderling gerelateerde componenten:

  • Een applicatieprogramma dat transactiegrenzen definieert en acties specificeert die een transactie vormen.
  • Bronnenbeheerders zoals databases of bestandssystemen die toegang bieden tot gedeelde bronnen.
  • Een transactiemanager die identifiers toewijst aan transacties, hun voortgang bewaakt en verantwoordelijkheid neemt voor het voltooien van transacties en het herstellen van fouten.

De XA-standaard definieert het tweefasige commit-protocol en de interface die wordt gebruikt voor communicatie tussen een transactiemanager en een resourcemanager. Het tweefasige commit-protocol biedt een alles-of-niets-garantie dat alle deelnemers die bij de transactie betrokken zijn, zich committeren of samen terugdraaien. De hele transactie wordt dus vastgelegd of de hele transactie wordt teruggedraaid.

De tweefasen-commit bestaat uit een voorbereidingsfase en een commit-fase. Tijdens de voorbereidingsfase moeten alle deelnemers aan de transactie akkoord gaan met het voltooien van de wijzigingen die vereist zijn voor de transactie. Als een van de deelnemers een probleem meldt, mislukt de voorbereidingsfase en wordt de transactie teruggedraaid. Als de voorbereidingsfase succesvol is, fase twee, begint de vastleggingsfase. Tijdens de vastleggingsfase instrueert de Transactiemanager alle deelnemers om de transactie door te voeren.

SQL Server en XA

Om XA-ondersteuning in SQL Server 2019 in te schakelen, volgt u de instructies in de sectie "De MS DTC-service uitvoeren" in dit document:

XA-transacties begrijpen

Volg de instructies in dit document om XA-ondersteuning in eerdere versies van SQL Server in te schakelen:

XA-transacties configureren in Microsoft SQL Server voor IBM Business Process Manager (BPM)

Het SQL Server ODBC-stuurprogramma is getest met XA-compatibele SQL Server 2016- en 2019-instanties.

Het Easysoft SQL Server ODBC-stuurprogramma

XA-ondersteuning is toegevoegd aan de SQL Server ODBC-driver in versie 1.11.3. De XA-ondersteuning van het stuurprogramma is getest met Oracle Tuxedo en SQL Server 2016 en 2019.

Om het SQL Server ODBC-stuurprogramma in te schakelen in een XA-transactie, moet u een structuur gebruiken met de naam es_xa_context in uw aanvraag. es_xa_context maakt verbinding met de ODBC-gegevensbron die u hebt opgegeven in uw XA resource manager-configuratie en retourneert een verbindingshandle. Bijvoorbeeld:

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

In Tuxedo, de ODBC-gegevensbron die es_xa_context verbindt met is gespecificeerd in de Resource Manager OPENINFO string in het Tuxedo-configuratiebestand. In dit voorbeeld is dat "SQLSERVER_SAMPLE":

OPENINFO="EASYSOFT_SQLSERVER_ODBC:DSN=SQLSERVER_SAMPLE"

De door het stuurprogramma gedefinieerde XA Resource Manager-naam en XA-switch zijn EASYSOFT_SQLSERVER_ODBC en essql_xaosw .

In Tuxedo specificeert u deze in het Tuxedo Resource Manager-definitiebestand, ${TUXDIR}/udataobj/RM . Bijvoorbeeld:

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

Voorbeeld Easysoft / Tuxedo / SQL Server XA-toepassing

Stel eerst een SQL Server ODBC-stuurprogrammagegevensbron in die verbinding maakt met een XA-enabled SQL Server-exemplaar:

  1. Installeer het SQL Server ODBC-stuurprogramma op uw Tuxedo-machine.
  2. Maak een SQL Server ODBC-stuurprogrammagegevensbron in odbc.ini. Bijvoorbeeld:
    [SQLSERVER_SAMPLE]
    Driver=Easysoft ODBC-SQL Server
    Description=Easysoft SQL Server ODBC driver
    Server=mymachine\myxaenabledinstance
    User=mydomain\myuser
    Password=mypassword
    Database=XA1
  3. Maak een voorbeeldtabel voor de Tuxedo-toepassing:
    $ /usr/local/easysoft/unixODBC/bin/isql.sh -v SQLSERVER_SAMPLE
    SQL> CREATE TABLE [dbo].[tx_test1]([i] [int] NULL,[c] [varchar](100) NULL)

Maak en voer de voorbeeldtoepassing Tuxedo XA uit.

  1. $ cd ~
    $ mkdir simpdir
    $ cd simpdir
    $ touch simpcl.c simpserv.c ubbsimple
  2. Voeg deze regels toe aan 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. Voeg deze regels toe aan 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. Voeg deze regels toe aan 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. Uw omgeving instellen:
    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. Bouw de voorbeeldclient:
    buildclient -o simpcl -f simpcl.c

    Als je de foutmelding "undefined reference to dlopen" krijgt bij het bouwen van de client, probeer dan dit commando:

    buildclient -o simpcl -f "-Xlinker --no-as-needed simpcl.c"
  7. Bouw de voorbeeldserver:
    buildserver -r EASYSOFT_SQLSERVER_ODBC -s EXECUTE -o simpserv -f "simpserv.c \
    -L/usr/local/easysoft/sqlserver/lib -lessqlsrv -lodbc"
  8. Maak het TUXCONFIG-bestand voor de voorbeeldtoepassing:
    tmloadcf ubbsimple
  9. Maak een Tuxedo-registratieapparaat voor de voorbeeldtoepassing:
    $ tmadmin -c
    > crdl -z /home/myuser/simpdir/tuxlog -b 512
  10. Bouw een Tuxedo-transactiemanager die communiceert met de SQL Server ODBC-driver:
    $ buildtms -o mySQLSERVER_TMS -r EASYSOFT_SQLSERVER_ODBC
  11. Start de voorbeeldserver op:
    $ tmboot
  12. Test de voorbeeldtoepassing:
    ./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. Als u de gegevens in de SQL Server-tabel ziet, sluit u de voorbeeldserver af:
    tmshutdown

    Raadpleeg anders ULOG.nnn in de voorbeeldtoepassingsmap.


  1. Verschil tussen TRIM() en TRIM_ORACLE() in MariaDB

  2. Kennis van het herstellen van verwijderde records in SQL Server

  3. Vereenvoudig gebruikersaccountbeheer met MariaDB MaxScale 2.2 en MariaDB Server 10.3

  4. het creëren van geparametriseerde views in oracle11g