【问题标题】:SQL ODBC - Concurrent transaction with INSERT-SELECT of foreign key informationSQL ODBC - 带有外键信息的 INSERT-SELECT 的并发事务
【发布时间】: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


    【解决方案1】:

    您是否考虑过在事务中使用 SCOPE_IDENTITY 将范围隔离到客户端上下文? https://docs.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql?view=sql-server-2017

    【讨论】:

    • 我没有使用 SCOPE IDENTITY 对其进行测试,但这与使用 OUTPUT 或 RETURNING 的情况类似。我正在寻找一种可以以类似方式用于所有数据库系统的机制。
    猜你喜欢
    • 1970-01-01
    • 2019-01-24
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    • 2011-10-25
    • 2013-12-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多