简体   繁体   中英

How to perform XA transactions using SQLServer client ODBC driver in C/C++ on Linux?

I've managed to perform XA transactions using SQLServer OLEDB driver on Windows. Now I've ported the C++ application to Linux. On Linux Microsoft provides the SQLServer 2019 ODBC driver and since version 17.3 of this driver, XA is reported to be supported. Microsoft provides following example that illustrates how to implement the xa_* functions:

Using XA Transactions

The example itself works. Using the code in another context doesn't work. The call to SQLSetConnectAttr(..., SQL_ATTR_ENLIST_IN_XA, ...) for operation OP_START fails and I don't get useful information by CheckRC().

  1. How to get more informaton about failing SQL_ATTR_ENLIST_IN_XA?
  2. How does XA work with the SQL_ATTR_ENLIST_IN_XA approach compared to OLEDB?
  3. Is it possible to change the isolation level in XA mode?

Share your experiences and details with us, please.

Strict XID data layout

The SQLSetConnectAttr(..., SQL_ATTR_ENLIST_IN_XA, ...) function is very sensitive regarding the XID. If the XID has a branch ID then the branch ID must start at byte 64 of xid_t::data. Storing a global ID like "f9707929-a367-4e3a-9a80-3fbb3a23ab11" + branch ID "1234" directly in one sequence and identifiying the string layout by xid_t::gtrid_length and xid_t::bqual_length will work with other DB APIs and IBM MQ, but it fails with SQL_ATTR_ENLIST_IN_XA in SQLServer.

In order to get above sample XID work the UUID has to be stored at the beginning of xid_t::data (byte 0-36) and the branch id has to be stored staring at byte (64-68). The xid_t field gtrid_length has to be set to 36 and bqual_length to 4. The formatID I set to 1.

If the XID layout doesn't fit the SQL_ATTR_ENLIST_IN_XA with operation OP_START fails and SQLGetDiagRec() reports nothing about it.

Setting the isolation level

By default a XA transaction runs under isolation level "Serializable". Microsoft describes this isolation leve as follows:

The highest level where transactions are completely isolated from one another. The SQLServer keeps read and write locks acquired on selected data to be released at the end of the transaction. Range-locks are acquired when a SELECT operation uses a ranged WHERE clause, especially to avoid phantom reads.

On each call to xa_start the isolation level is set to "Serializable". Setting the isolation level using SQLSetConnectAttr(..., SQL_ATTR_TXN_ISOLATION, ...) after connect doesn't help. You have to call this after SQLSetConnectAttr(..., SQL_ATTR_ENLIST_IN_XA, OP_START, ...).

Doing so allows you to set the isolation level for instance to SQL_TXN_READ_COMMITTED. The database option READ_COMMITTED_SNAPSHOT will be also be considered. This means setting isolation level to SQL_TXN_READ_COMMITTED and having database option READ_COMMITTED_SNAPSHOT enabled will switch the isolation level to "Snapshot".

The command "DBCC useroptions" can be used to query the isolation level of the current session.

Following query is also useful for checking the isolation level and status of active transactions:

SELECT tst.session_id, [database_name] = db_name(s.database_id)
, tat.transaction_begin_time
, transaction_duration_s = datediff(s, tat.transaction_begin_time, sysdatetime()) 
, transaction_type = CASE tat.transaction_type  WHEN 1 THEN 'Read/write transaction'
                                                WHEN 2 THEN 'Read-only transaction'
                                                WHEN 3 THEN 'System transaction'
                                                WHEN 4 THEN 'Distributed transaction' END
, input_buffer = ib.event_info, tat.transaction_uow     
, transaction_state  = CASE tat.transaction_state    
            WHEN 0 THEN 'The transaction has not been completely initialized yet.'
            WHEN 1 THEN 'The transaction has been initialized but has not started.'
            WHEN 2 THEN 'The transaction is active - has not been committed or rolled back.'
            WHEN 3 THEN 'The transaction has ended. This is used for read-only transactions.'
            WHEN 4 THEN 'The commit process has been initiated on the distributed transaction.'
            WHEN 5 THEN 'The transaction is in a prepared state and waiting resolution.'
            WHEN 6 THEN 'The transaction has been committed.'
            WHEN 7 THEN 'The transaction is being rolled back.'
            WHEN 8 THEN 'The transaction has been rolled back.' END 
, trn_iso_level = CASE s.transaction_isolation_level
           WHEN 0 THEN 'Unspecified'
           WHEN 1 THEN 'ReadUncommitted'
           WHEN 2 THEN 'ReadCommitted'
           WHEN 3 THEN 'RepeatableRead'
           WHEN 4 THEN 'Serializable'
           WHEN 5 THEN 'Snapshot' END            
, transaction_name = tat.name, request_status = r.status
, tst.is_user_transaction, tst.is_local
, session_open_transaction_count = tst.open_transaction_count  
, s.host_name, s.program_name, s.client_interface_name, s.login_name, s.is_user_process
FROM sys.dm_tran_active_transactions tat 
INNER JOIN sys.dm_tran_session_transactions tst  on tat.transaction_id = tst.transaction_id
INNER JOIN Sys.dm_exec_sessions s on s.session_id = tst.session_id 
LEFT OUTER JOIN sys.dm_exec_requests r on r.session_id = s.session_id
CROSS APPLY sys.dm_exec_input_buffer(s.session_id, null) AS ib;

The Advantage of SQLServer ODBC driver SQL_ATTR_ENLIST_IN_XA

Implementing SQLServer XA with the OLEDB driver and ITransactionJoin interface directly communicates with the local distributed transaction controller (DTC) service. In case the SQLServer is running on another host then the local DTC and the DTC on the SQLServer host are involved. The DTC service must communicate over network. RPC, dynamic port ranges, firewall and security settings often makes this very difficult getting it to work.

With the new ODBC SQL_ATTR_ENLIST_IN_XA interace the DTC to DTC communication is no longer needed. The appliction has only a connection to the SQLServer database instance and on the SQLServer host the DTC service must run and the "XA option" must be set in this DTC. The application that utilizes SQL_ATTR_ENLIST_IN_XA doesn't require a local DTC.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM