如何在 ODBC 中启动事务?

How to start a transaction in ODBC?

如何在 ODBC 中启动事务?具体来说,我碰巧正在处理 SQL 服务器,但这个问题适用于任何数据源。

在原生 T-SQL 中,您发出命令:

BEGIN TRANSACTION
--...
COMMIT TRANSACTION
--or ROLLBACK TRANSACTION

在ADO.net中,您调用:

DbConnection conn = new SqlConnection();
DbTransaction tx = conn.BeginTransaction();
//...
tx.Commit();
//or tx.Rollback();

在 OLE DB 中调用:

IDBInitialize init = new MSDASQL();
IDBCreateSession session = (init as IDBCreateSession).CreateSession();
(session as ITransactionLocal).StartTransaction(ISOLATIONLEVEL_READCOMMITTED, 0, null, null);
//...
(session as ITransactionLocal).Commit();
//or (session as ITransactionLocal).Rollback();

在 ADO 中调用:

Connection conn = new Connection();
conn.BeginTrans();
//...
conn.CommitTrans();
//or conn.RollbackTrans();

ODBC 呢?

对于 ODBC,Microsoft 在他们的页面上给出了提示 Transactions in ODBC:

An application calls SQLSetConnectAttr to switch between the two ODBC modes of managing transactions:

  • Manual-commit mode

    All executed statements are included in the same transaction until it is specifically stopped by calling SQLEndTran.

这意味着我只需要知道要传递给哪些参数 SQLSetConnectAttr:

HENV environment;
SQLAllocEnv(&environment);
HDBC conn;
SQLAllocConnect(henv, &conn);

SQLSetConnectAttr(conn, {attribute}, {value}, {stringLength});
//...
SQLEndTran(SQL_HANDLE_ENV, environment, SQL_COMMIT);
//or SQLEndTran(SQL_HANDLE_ENV, environment, SQL_ROLLBACK);

但是页面并没有真正给出任何关于哪个参数将启动事务的提示。可能是:

SQL_COPT_SS_ENLIST_IN_XA

To begin an XA transaction with an XA-compliant Transaction Processor (TP), the client calls the Open Group tx_begin function. The application then calls SQLSetConnectAttr with a SQL_COPT_SS_ENLIST_IN_XA parameter of TRUE to associate the XA transaction with the ODBC connection. All related database activity will be performed under the protection of the XA transaction. To end an XA association with an ODBC connection, the client must call SQLSetConnectAttr with a SQL_COPT_SS_ENLIST_IN_XA parameter of FALSE. For more information, see the Microsoft Distributed Transaction Coordinator documentation.

但由于我从未听说过 XA,我也不需要 MSDTC 运行,我认为不是这样。


丸尾回答了。但要澄清:

HENV environment;
SQLAllocEnv(&environment);
HDBC conn;
SQLAllocConnect(henv, &conn);

SQLSetConnectAttr(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER);
//...
SQLEndTran(SQL_HANDLE_ENV, environment, SQL_COMMIT);
//or SQLEndTran(SQL_HANDLE_ENV, environment, SQL_ROLLBACK);

SQLSetConnectAttr(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON, SQL_IS_UINTEGER);

ODBC 可以在两种模式下运行:AUTOCOMMIT_ON 和AUTOCOMMIT_OFF。默认值为 AUTOCOMMIT_ON。当自动提交打开时,您开始使用与该连接关联的会话句柄的每个命令都将被自动提交。

让我们看看 "manual commit"(别名 AUTOCOMMIT_OFF)是如何工作的。

首先你关闭AUTOCOMMIT使用这样的东西:

if (!SQL_SUCCEEDED(Or=SQLSetConnectAttr(Oc, SQL_ATTR_AUTOCOMMIT,   
                      (SQLPOINTER)SQL_AUTOCOMMIT_OFF,
                       SQL_IS_UINTEGER))) {
// error handling here
}

其中 "Oc" 是连接句柄。

第二个 你 运行 像往常一样执行所有命令:准备/执行语句、绑定参数等....没有针对 "START" 的特定命令一笔交易。关闭自动提交后的所有命令都是事务的一部分。

第三次 你提交:

if (!SQL_SUCCEEDED(Or=SQLEndTran(SQL_HANDLE_DBC, Oc, SQL_COMMIT))) {
// Error handling
}

而且 - 同样 - 从现在开始,所有新命令都会自动成为新事务的一部分,您将必须使用另一个 SQLEndTran 命令提交该事务,如上所示。

终于...再次切换AUTOCOMMIT_ON:

if (!SQL_SUCCEEDED(Or=SQLSetConnectAttr(Oc, SQL_ATTR_AUTOCOMMIT, 
                  (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_IS_UINTEGER))) {
 // Error Handling
}