This example shows the steps that a C or C++ application takes to use DB-Library to update two SQL Servers within an MS DTC transaction. It shows the OLE transaction calls for initiating and committing MS DTC transactions as well as the DB-Library call to propagate an MS DTC transaction from the application to SQL Server. Note that the complete DB-Library example is not shown here but it can be found in the Microsoft SQL Server Programmer's Toolkit.
These are the steps that the application performs:
The application passes two parameters to dbenlisttrans. The first parameter is the database process structure (DBPROC), which identifies the SQL Server connection. The second parameter is a pointer to the MS DTC transaction object. To learn more about dbenlisttrans, see What's New in SQL Server 6.5.
You cannot use the DB-Library database connections until ITransaction::Commit completes and you call dbenlisttrans to enlist in a new MS DTC transaction. If you reuse the DB-Library connection before doing this, an error will result.
Note If you have used a DB-Library connection with an MS DTC transaction and you want to use the same DB-Library connection with a local SQL Server transaction, you must first call dbenlisttrans and pass a NULL transaction. By passing a NULL transaction to the DB-Library dbenlisttrans function, you instruct SQL Server to use local SQL Server transactions.
void main(int argc, char **argv) { ITransactionDispenser *pTransactionDispenser; ITransaction *pTransaction; HRESULT hr = S_OK ; TCHAR SqlStatement[STR_LEN*2]; // Initialize globals & validate command line arguments InitGlobals(argc,argv); // set error/msg handlers for this program dbmsghandle((DBMSGHANDLE_PROC)msg_handler); dberrhandle((DBERRHANDLE_PROC)err_handler); // initialize LOGINREC structure login = dblogin(); // Obtain the ITransactionDispenser Interface pointer // by calling DtcGetTransactionManager() hr = DtcGetTransactionManager( NULL, // LPTSTR pszHost, NULL, // LPTSTR pszTmName, IID_ITransactionDispenser, // REFIID rid, 0, // DWORD dwReserved1, 0, // WORD wcbReserved2, 0, // void FAR * pvReserved2, (void **)&pTransactionDispenser // void** ppvObject) ; if (FAILED (hr)) { printf("DtcGetTransactionManager failed: %x\n", hr); exit (1); } // Establish connection to database on server#1 LogonToDB(&dbproc_server1,&gSrv1); // Establish connection to database on server#2 LogonToDB(&dbproc_server2,&gSrv2); // Loop performing distributed transactions for (INT i = 0; i < 5; i++) { // Initiate an MS DTC transaction hr = pTransactionDispenser->BeginTransaction( NULL, // IUnknown __RPC_FAR *punkOuter, ISOLATIONLEVEL_ISOLATED, // ISOLEVEL isoLevel, ISOFLAG_RETAIN_DONTCARE, // ULONG isoFlags, NULL, // ITransactionOptions *pOptions &pTransaction // ITransaction **ppTransaction) ; if (FAILED (hr)) { printf("BeginTransaction failed: %x\n",hr); exit(1); } // Enlist each of the data sources on the transaction Enlist(&gSrv1,dbproc_server1,pTransaction); Enlist(&gSrv2,dbproc_server2,pTransaction); // Generate the SQL statement to execute on each // of the databases sprintf(SqlStatement, "update authors set address = '%s_%d' where au_id = '%s'", gNewAddress,i,gAuthorID); // Perform updates on both of the DBs participating // in the transaction ExecuteStatement(&gSrv1,dbproc_server1,SqlStatement); ExecuteStatement(&gSrv2,dbproc_server2,SqlStatement); // Commit the transaction hr = pTransaction->Commit(0,0,0); if (FAILED(hr)) { printf("pTransaction->Commit() failed: %x\n",hr); exit(1); } // At end of each transaction, pTransaction-Release() // must be called. hr = pTransaction->Release(); if (FAILED(hr)) { printf("pTransaction->Release() failed: %x\n",hr); exit(1); } printf("Successfully committed Transaction #%d\n",i); } // for // release the transaction dispenser pTransactionDispenser->Release(); // release DBLib resources and exit dbexit(); } void LogonToDB(DBPROCESS **dbp, DBCONN *ptr) { DBSETLUSER(login, ptr->pszUser); DBSETLPWD(login, ptr->pszPasswd); DBSETLAPP(login, "example"); *dbp = dbopen (login, ptr->pszSrv); if (*dbp == NULL) { printf ("\nLogin to server: %s failed, exiting!\n",ptr->pszSrv); exit (ERREXIT); } /* Use the "pubs" database. */ dbuse(*dbp, "pubs"); } void Enlist(DBCONN *ptr, DBPROCESS *dbp, ITransaction *pTransaction) { RETCODE rc = 0; rc = dbenlisttrans (dbp, pTransaction); if (FAIL == rc) { printf("\ndbenlisttrans() failed: %x\n",rc); exit(1); } } void ExecuteStatement(DBCONN *ptr, DBPROCESS *dbp, char *pszBuf) { RETCODE rc = 0; dbcmd(dbp,pszBuf); rc = dbsqlexec(dbp); if (FAIL == rc) { printf("dbsqlexec() failed\n"); exit(1); } rc = dbresults(dbp); if (rc != SUCCEED) { printf("dbresults() failed: %x\n",rc); exit(1); } }