Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Включване на SQL Server в разпределена XA транзакция

Как да получите достъп до SQL Server в контекста на XA транзакция с Easysoft SQL Server ODBC драйвер и Oracle Tuxedo.

Въведение

Защо са необходими разпределени транзакции

Транзакцията е поредица от действия, извършвани като една операция, при която или се изпълняват всички действия, или нито едно от тях. Транзакцията завършва с действие на ангажимент, което прави промените постоянни. Ако някоя от промените не може да бъде ангажирана, транзакцията ще се върне назад, като отмени всички промени.

Разпределената транзакция е транзакция, която може да обхваща множество ресурси. Например една или повече бази данни или база данни и опашка за съобщения. За да бъде транзакцията успешна, всички индивидуални ресурси трябва да се ангажират успешно; ако някой от тях е неуспешен, транзакцията трябва да се върне обратно във всички ресурси. Например, разпределена транзакция може да се състои от паричен превод между две банкови сметки, хоствани от различни банки, и така също в различни бази данни. Не бихте искали нито една транзакция да бъде извършена без гаранция, че и двете ще завършат успешно. В противен случай данните могат да бъдат дублирани (ако вмъкването завърши и изтриването не е успешно) или загубени (ако изтриването завърши и вмъкването не успее).

Следователно, когато едно приложение трябва да получи достъп или да актуализира данните в множество транзакционни ресурси, то трябва да използва разпределена транзакция. Възможно е да се използва отделна транзакция за всеки от ресурсите, но този подход е податлив на грешки. Ако транзакцията в един ресурс се ангажира успешно, но друг се провали и трябва да се върне назад, първата транзакция вече не може да бъде връщана назад, така че състоянието на приложението става непоследователно. Ако един ресурс извърши успешно ангажимент, но системата се срине, преди другият ресурс да може да извърши успешно ангажимент, приложението отново е непоследователно.

XA

Моделът X/Open Distributed Transaction Processing (DTP) дефинира архитектура за обработка на разпределени транзакции. В архитектурата на DTP координиращият мениджър на транзакции казва на всеки ресурс как да обработи транзакция, въз основа на познанията си за всички ресурси, участващи в транзакцията. Ресурсите, които обикновено управляват собствените си транзакции за извършване и възстановяване, делегират тази задача на мениджъра на транзакциите.

Спецификацията XA на архитектурата предоставя отворен стандарт, който гарантира оперативна съвместимост между съвместими транзакционни междинни продукти и продукти за бази данни. Следователно тези различни ресурси могат да участват заедно в разпределена транзакция.

DTP моделът включва три взаимосвързани компонента:

  • Приложна програма, която дефинира границите на транзакцията и уточнява действия, които съставляват транзакция.
  • Мениджъри на ресурси като бази данни или файлови системи, които осигуряват достъп до споделени ресурси.
  • Мениджър на транзакции, който присвоява идентификатори на транзакциите, наблюдава техния напредък и поема отговорността за приключването на транзакциите и възстановяването при неуспех.

Стандартът XA дефинира двуфазния протокол за записване и интерфейса, използван за комуникация между мениджър на транзакции и мениджър на ресурси. Протоколът за двуфазен комит предоставя гаранция за всичко или нищо, че всички участници, участващи в транзакцията, или се ангажират, или ще се върнат заедно. Следователно цялата транзакция се ангажира или цялата транзакция се връща назад.

Двуфазният комит се състои от фаза на подготовка и фаза на комит. По време на фазата на подготовка всички участници в транзакцията трябва да се съгласят да завършат промените, изисквани от транзакцията. Ако някой от участниците съобщи за проблем, фазата на подготовка ще се провали и транзакцията ще се върне обратно. Ако подготвителната фаза е успешна, фаза втора, започва фазата на записване. По време на фазата на извършване, Мениджърът на транзакции инструктира всички участници да извършат транзакцията.

SQL сървър и XA

За да активирате поддръжката на XA в SQL Server 2019, следвайте инструкциите в раздела „Изпълнение на услугата MS DTC“, съдържащ се в този документ:

Разбиране на XA транзакции

За да активирате поддръжката на XA в по-ранни версии на SQL Server, следвайте инструкциите в този документ:

Конфигуриране на XA транзакции в Microsoft SQL Server за IBM Business Process Manager (BPM)

ODBC драйверът на SQL Server е тестван с екземпляри на SQL Server 2016 и 2019 с активиран XA.

Драйверът ODBC на Easysoft SQL Server

Поддръжката на XA беше добавена към драйвера на ODBC на SQL Server във версия 1.11.3. Поддръжката на XA на драйвера е тествана с Oracle Tuxedo и SQL Server 2016 и 2019.

За да включите ODBC драйвера на SQL Server в XA транзакция, трябва да използвате структура с име es_xa_context във вашето приложение. es_xa_context се свързва с източника на данни ODBC, който сте посочили в конфигурацията на вашия XA ресурсен мениджър, и връща манипулатор на връзката. Например:

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

В Tuxedo, източникът на ODBC данни, който es_xa_context се свързва с е посочено в диспечера на ресурси OPENINFO низ в конфигурационния файл Tuxedo. В този пример това е "SQLSERVER_SAMPLE":

OPENINFO="EASYSOFT_SQLSERVER_ODBC:DSN=SQLSERVER_SAMPLE"

Дефинираното от драйвера име на XA Resource Manager и превключвател XA са EASYSOFT_SQLSERVER_ODBC и essql_xaosw .

В Tuxedo ги посочвате във файла с дефиниция на Tuxedo Resource Manager, ${TUXDIR}/udataobj/RM . Например:

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

Примерно приложение Easysoft / Tuxedo / SQL Server XA

Първо, настройте източник на данни за драйвер на SQL Server ODBC, който се свързва с екземпляр на SQL Server с активиран XA:

  1. На вашата Tuxedo машина инсталирайте ODBC драйвера на SQL Server.
  2. Създайте източник на данни за драйвер на SQL Server ODBC в odbc.ini. Например:
    [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)

Създайте и стартирайте примерното приложение Tuxedo XA.

  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

    Ако получите грешката „undefined reference to 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. Създайте мениджър на транзакции Tuxedo, който взаимодейства с ODBC драйвера на SQL Server:
    $ 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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да използвате клаузата Where в Select Statement в SQL Server - SQL Server / TSQL Урок, част 109

  2. Как работи операторът IF в SQL Server

  3. RADIANS() Примери в SQL Server

  4. 3 начина за конвертиране на HEX в INT в SQL Server (T-SQL)

  5. Вмъкване в... Обединяване... Изберете (SQL сървър)