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:
- Na vašem počítači Tuxedo nainstalujte ovladač SQL Server ODBC.
- 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
- 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.
-
$ cd ~ $ mkdir simpdir $ cd simpdir $ touch simpcl.c simpserv.c ubbsimple
- 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); }
- 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); } }
- 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
- 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
- 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"
- Sestavte ukázkový server:
buildserver -r EASYSOFT_SQLSERVER_ODBC -s EXECUTE -o simpserv -f "simpserv.c \ -L/usr/local/easysoft/sqlserver/lib -lessqlsrv -lodbc"
- Vytvořte soubor TUXCONFIG pro ukázkovou aplikaci:
tmloadcf ubbsimple
- Vytvořte protokolovací zařízení Tuxedo pro ukázkovou aplikaci:
$ tmadmin -c > crdl -z /home/myuser/simpdir/tuxlog -b 512
- Sestavte správce transakcí Tuxedo, který je propojen s ovladačem SQL Server ODBC:
$ buildtms -o mySQLSERVER_TMS -r EASYSOFT_SQLSERVER_ODBC
- Spusťte ukázkový server:
$ tmboot
- 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 | +------------+--------------+
- 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.