sql >> Database teknologi >  >> RDS >> Sqlserver

Indrullering af SQL Server i en distribueret XA-transaktion

Sådan får du adgang til SQL Server i forbindelse med en XA-transaktion med Easysoft SQL Server ODBC-driveren og Oracle Tuxedo.

Introduktion

Hvorfor er der behov for distribuerede transaktioner

En transaktion er en række handlinger, der udføres som en enkelt operation, hvor enten alle handlingerne udføres, eller ingen af ​​dem udføres. En transaktion ender med en commit-handling, der gør ændringerne permanente. Hvis nogen af ​​ændringerne ikke kan forpligtes, vil transaktionen rulle tilbage og tilbageføre alle ændringerne.

En distribueret transaktion er en transaktion, der kan spænde over flere ressourcer. For eksempel en eller flere databaser eller en database og en beskedkø. For at transaktionen skal forpligtes med succes, skal alle de individuelle ressourcer forpligte sig med succes; hvis nogen af ​​dem ikke lykkes, skal transaktionen rulle tilbage i alle ressourcerne. For eksempel kan en distribueret transaktion bestå af en pengeoverførsel mellem to bankkonti, hostet af forskellige banker, og så også på forskellige databaser. Du ønsker ikke, at nogen af ​​transaktionerne udføres uden en garanti for, at begge vil gennemføres med succes. Ellers kan data duplikeres (hvis indsættelsen fuldføres, og sletningen mislykkes) eller gå tabt (hvis sletningen fuldføres, og indsættelsen mislykkes).

Når en applikation skal have adgang til eller opdatere dataene i flere transaktionsressourcer, bør den derfor bruge en distribueret transaktion. Det er muligt at bruge en separat transaktion på hver af ressourcerne, men denne tilgang er udsat for fejl. Hvis transaktionen i en ressource forpligtes, men en anden mislykkes og skal rulle tilbage, kan den første transaktion ikke længere rulles tilbage, så applikationens tilstand bliver inkonsekvent. Hvis en ressource commiterer med succes, men systemet går ned, før den anden ressource kan commiterer med succes, er applikationen igen inkonsekvent.

XA

X/Open Distributed Transaction Processing (DTP)-modellen definerer en arkitektur for distribueret transaktionsbehandling. I DTP-arkitekturen fortæller en koordinerende transaktionsadministrator hver ressource, hvordan en transaktion skal behandles, baseret på dens viden om alle de ressourcer, der deltager i transaktionen. Ressourcer, der normalt administrerer deres egen transaktionsbekræftelse og -gendannelse, uddelegerer denne opgave til transaktionsadministratoren.

Arkitekturens XA-specifikation giver en åben standard, der sikrer interoperabilitet på tværs af konforme transaktions-middleware og databaseprodukter. Disse forskellige ressourcer er derfor i stand til at deltage sammen i en distribueret transaktion.

DTP-modellen inkluderer tre indbyrdes forbundne komponenter:

  • Et applikationsprogram, der definerer transaktionsgrænser og specificerer handlinger, der udgør en transaktion.
  • Ressourceadministratorer såsom databaser eller filsystemer, der giver adgang til delte ressourcer.
  • En Transaction Manager, der tildeler identifikatorer til transaktioner, overvåger deres fremskridt og tager ansvar for transaktionsgennemførelse og fejlgendannelse.

XA-standarden definerer den to-fasede commit-protokol og den grænseflade, der bruges til kommunikation mellem en Transaction Manager og en Resource Manager. To-fase commit-protokollen giver en alt-eller-intet-garanti for, at alle deltagere, der er involveret i transaktionen, enten forpligter sig eller ruller tilbage sammen. Hele transaktionen commits eller hele transaktionen ruller tilbage, derfor.

Den tofasede commit består af en forberedelsesfase og en commitfase. Under forberedelsesfasen skal alle deltagere i transaktionen acceptere at gennemføre de ændringer, som transaktionen kræver. Hvis nogen af ​​deltagerne rapporterer et problem, vil forberedelsesfasen mislykkes, og transaktionen vil rulle tilbage. Hvis forberedelsesfasen er vellykket, fase to, starter commit-fasen. Under forpligtelsesfasen instruerer Transaction Manager alle deltagere om at forpligte transaktionen.

SQL-server og XA

For at aktivere XA-understøttelse i SQL Server 2019 skal du følge instruktionerne i afsnittet "Køre MS DTC-tjenesten" i dette dokument:

Forstå XA-transaktioner

For at aktivere XA-understøttelse i tidligere versioner af SQL Server skal du følge instruktionerne i dette dokument:

Konfiguration af XA-transaktioner i Microsoft SQL Server til IBM Business Process Manager (BPM)

SQL Server ODBC-driveren er blevet testet med XA-aktiverede SQL Server 2016- og 2019-instanser.

Easysoft SQL Server ODBC-driveren

XA-understøttelse blev tilføjet til SQL Server ODBC-driver i version 1.11.3. Driverens XA-understøttelse er blevet testet med Oracle Tuxedo og SQL Server 2016 og 2019.

For at inddrage SQL Server ODBC-driveren i en XA-transaktion skal du bruge en struktur med navnet es_xa_context i din ansøgning. es_xa_context opretter forbindelse til den ODBC-datakilde, du har angivet i din XA-ressourcestyringskonfiguration og returnerer et forbindelseshåndtag. For eksempel:

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

I Tuxedo er ODBC-datakilden, der es_xa_context forbinder til er angivet i Ressourcestyring OPENINFO streng i Tuxedo-konfigurationsfilen. I dette eksempel er det "SQLSERVER_SAMPLE":

OPENINFO="EASYSOFT_SQLSERVER_ODBC:DSN=SQLSERVER_SAMPLE"

Det driverdefinerede XA Resource Manager-navn og XA-switch er EASYSOFT_SQLSERVER_ODBC og essql_xaosw .

I Tuxedo angiver du disse i Tuxedo Resource Manager-definitionsfilen, ${TUXDIR}/udataobj/RM . For eksempel:

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

Eksempel på Easysoft / Tuxedo / SQL Server XA-applikation

Først skal du konfigurere en SQL Server ODBC-driverdatakilde, der forbinder til en XA-aktiveret SQL Server-instans:

  1. På din Tuxedo-maskine skal du installere SQL Server ODBC-driveren.
  2. Opret en SQL Server ODBC-driverdatakilde i odbc.ini. For eksempel:
    [SQLSERVER_SAMPLE]
    Driver=Easysoft ODBC-SQL Server
    Description=Easysoft SQL Server ODBC driver
    Server=mymachine\myxaenabledinstance
    User=mydomain\myuser
    Password=mypassword
    Database=XA1
  3. Opret en eksempeltabel til Tuxedo-applikationen:
    $ /usr/local/easysoft/unixODBC/bin/isql.sh -v SQLSERVER_SAMPLE
    SQL> CREATE TABLE [dbo].[tx_test1]([i] [int] NULL,[c] [varchar](100) NULL)

Opret og kør prøven Tuxedo XA Application.

  1. $ cd ~
    $ mkdir simpdir
    $ cd simpdir
    $ touch simpcl.c simpserv.c ubbsimple
  2. Tilføj disse linjer til 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. Tilføj disse linjer til 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. Tilføj disse linjer til 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. Indstil dit miljø:
    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. Byg prøveklienten:
    buildclient -o simpcl -f simpcl.c

    Hvis du får fejlen "undefined reference to dlopen", når du bygger klienten, så prøv denne kommando i stedet:

    buildclient -o simpcl -f "-Xlinker --no-as-needed simpcl.c"
  7. Byg prøveserveren:
    buildserver -r EASYSOFT_SQLSERVER_ODBC -s EXECUTE -o simpserv -f "simpserv.c \
    -L/usr/local/easysoft/sqlserver/lib -lessqlsrv -lodbc"
  8. Opret TUXCONFIG-filen til eksempelapplikationen:
    tmloadcf ubbsimple
  9. Opret en Tuxedo-logningsenhed til eksempelapplikationen:
    $ tmadmin -c
    > crdl -z /home/myuser/simpdir/tuxlog -b 512
  10. Byg en Tuxedo-transaktionsadministrator, der har grænseflader med SQL Server ODBC-driveren:
    $ buildtms -o mySQLSERVER_TMS -r EASYSOFT_SQLSERVER_ODBC
  11. Start prøveserveren:
    $ tmboot
  12. Test eksempelapplikationen:
    ./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. Hvis du ser dataene i SQL Server-tabellen, skal du lukke prøveserveren ned:
    tmshutdown

    Ellers skal du konsultere ULOG.nnn i eksempelprogrambiblioteket.


  1. execSQL() med OPDATERING opdateres ikke

  2. Sådan giver du alle privilegier på en database i MySQL

  3. 3 måder at returnere tidszonen fra en DateTime-værdi i Oracle

  4. Migrering af en Oracle-database fra AWS EC2 til AWS RDS, del 2