【发布时间】:2019-09-12 12:48:10
【问题描述】:
我正在实现一个 ODBC 应用程序,其中多个客户端将数据存储在两个具有外键关系的表中。这个应用程序应该以类似的方式支持不同的数据库。因此 sql 命令被外部化在文件中,并且应该以类似的结构编写。
为了缩小范围,我有一个基于 SQL Server 语法的简化示例:
CREATE TABLE A
(
id int IDENTITY(1,1) PRIMARY KEY,
name varchar(max) NO NULL
);
CREATE TABLE B
(
id int IDENTITY(1,1) PRIMARY KEY,
data varchar(max) NO NULL,
A_id int NOT NULL,
FOREIGN KEY (A_id) REFERENCES A (id) ON DELETE CASCADE ON UPDATE CASCADE
);
这些值由以下 SQL 代码通过SQLExecDirect 插入:
BEGIN TRANSACTION;
INSERT INTO A (name)
VALUES ('John');
INSERT INTO B (data)
VALUES ('Some data', (SELECT MAX(id) FROM A));
COMMIT TRANSACTION;
我设置了以下语句属性:
SQLSetStmtAttr(hStmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER)SQL_CONCUR_LOCK, 0));
SQLSetStmtAttr(hStmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER) SQL_CURSOR_KEYSET_DRIVEN, 0));
SQLSetStmtAttr(hStmt, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER)300, SQL_IS_UINTEGER));
自动提交的连接属性被禁用:
SQLSetConnectOption(m_hDBC, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
当从两个客户端并行测试时,我遇到的情况是,A 的最大主键不是来自当前事务的主键,而是来自另一个客户端的主键。
换句话说,从客户端 1 到表 A 的 INSERT 命令对客户端 2 的 INSERT-SELECT 子句可见。如何避免这种情况?
顺便说一句,我知道我可以使用 OUTPUT 在 SQL Serer 的第一个 INSERT 语句中检索主键。其他一些 SQL 方言有 RETURNING,但也有一些方言不提供返回此 ID 的可能性,因此我喜欢远离这种技术,并喜欢使用带有表 A 的最大 id 的嵌套 SELECT 的 INSERT .
我想知道我缺少什么来保存这笔交易。
【问题讨论】:
标签: sql-server concurrency transactions odbc