sqlite ON CONFLICT ROLLBACK和连续查询

时间:2014-03-01 00:14:12

标签: sqlite transactions

我使用sqlite ON CONFLICT ROLLBACK子句来保存可能被占用的资源表。这是通过重复的语句完成的,这些语句在事务中运行得非常有效。像这样:

BEGIN TRANSACTION;
INSERT INTO places (place) VALUES(17);
INSERT INTO places (place) VALUES(18);
INSERT INTO places (place) VALUES(19);
COMMIT;

这些地方受... place UNIQUE ON CONFLICT ROLLBACK ...子句的约束。

然而,似乎交易对这种用途并不理智。实际上,如果发生一个UNIQE冲突,即使我们没有点击COMMIT语句,也会回滚转移。 COMMITCOMMIT之前的以下语句似乎已经执行,现在作为具有隐式提交的单个语句。这种行为不是没用吗?我希望在调用COMMIT之前不会发生任何事情,ROLLBACK会导致BEGIN之前的状态触发。

为什么会这样?

2 个答案:

答案 0 :(得分:0)

冲突解决条款的范围始终是当前语句,而不是以下任何语句。 这适用于documented

当程序遇到错误时,通常会修复导致错误的任何内容并重试该语句,或者执行另一个语句。 因此,数据库假定您执行的任何命令都是您实际要执行的命令。

ON CONFLICT ROLLBACK子句对您的应用程序没有意义。 您应该使用正常的ON CONFLICT ABORT算法,并通过不执行任何以下命令来处理冲突:

try:
    db.execute("BEGIN")
    db.execute("INSERT INTO places(place) VALUES(17)")
    db.execute("INSERT INTO places(place) VALUES(18)")
    db.execute("INSERT INTO places(place) VALUES(19)")
    db.execute("COMMIT")
except:
    db.execute("ROLLBACK")

或在单个语句中插入所有值,以便任何ABORT自动回滚其他值:

INSERT INTO places(place) VALUES (17), (18), (19)

答案 1 :(得分:0)

我确认使用 .Net绑定System.Data.SQLite 1.0.110.0 SQLite版本3.27.2 ,问题中提到的ON CONFLICT子句有效符合OP的要求,也符合documentation explains

问题中既没有提供特定版本(除了sqlite3标记),也没有提供足够的DDL代码,也不提供有关编码环境的任何详细信息,以确保确定为什么该语句无法按预期工作。因此,此答案是对主要问题的更新参考,而不是针对OP特定情况的解决方案。

但是,在使用上面给出的最新版本直接在C#代码中测试... UNIQUE ON CONFLICT ROLLBACK子句之前,我确实遇到了与问题中所述类似的行为。我首先尝试使用第三方工具 SQLiteStudio v3.2.1(使用SQLite 3.24.0)用于SQLite 3.11.2的数据库浏览器(使用SQLite 3.27.2)测试代码。< / em>。经过许多令人沮丧的测试之后,我现在假设这两个工具都实现了自己的语句/事务处理和/或编译选项,这些似乎完全弄乱了SQLite的基础事务行为。对于这两种工具,似乎ON CONFLICT语句的CREATE TABLE子句会引起错误的,错误的交易行为。例如,即使该事务看似已回滚并返回了错误,DB Broswer仍允许提交假定事务中的各个语句!在这方面,我遇到了问题中所描述的问题,但事实证明问题并非直接与SQLite有关,而是与第三方工具有关。

直到我使用C#代码进行直接测试(连接上没有任何其他活动),我才能够确认SQLite3正确处理了表列上的ON CONFLICT声明。这也是有关第三方工具尝试自动管理SQLite数据库的警告。为提供管理功能而对数据库进行的所有其他调用都可能干扰本来有效的SQL语句和事务。


我首先使用以下SQL语句设置一个表:

CREATE TABLE places (
    id     INTEGER    PRIMARY KEY
                      AUTOINCREMENT
                      NOT NULL
                      UNIQUE,
    place  INTEGER    NOT NULL
                      UNIQUE ON CONFLICT ROLLBACK);

INSERT INTO places (place) VALUES (10);
INSERT INTO places (place) VALUES (18);
INSERT INTO places (place) VALUES (5);

接下来,我在显式事务中执行了其他插入操作:

BEGIN TRANSACTION;
INSERT INTO places (place) VALUES (17);
INSERT INTO places (place) VALUES (18); --Should fail due to non-unique value
INSERT INTO places (place) VALUES (19);
COMMIT;

分别执行每个准备好的语句(在单独的SQLite.SQLiteCommand对象中)后,指示的语句失败,导致事务的ROLLBACK。我通过检查查询SQLiteConnection.AutoCommit属性(如果在显式事务中返回false)的连接状态,还尝试了显式ROLLBACK并失败,并显示错误,指出没有事务,从而验证了回滚活跃。为了进一步验证没有其他语句被意外提交,我从另一个进程中查询了数据库,发现没有其他行被插入和提交。