预处理语句执行结果是否受初始化位置影响?未提交事务是否被考量?
SQLite预处理语句执行结果与初始化位置的关系
预处理语句的执行结果会因其初始化位置不同而存在差异,具体来说:预处理语句的查询是否纳入未提交变更的考量,完全取决于该语句是否与事务在同一数据库连接中初始化。
跨连接初始化的情况(断言失败)
当预处理语句在一个连接中创建后关闭该连接,后续在新连接的事务中执行该语句时,无法感知新连接里的未提交变更:
// 打开数据库、预处理语句、关闭连接 sqlite3* db = nullptr; sqlite3_open(filename, &db); sqlite3_stmt* count_stmt = nullptr; sqlite3_prepare_v3(db, "SELECT count(*) FROM names", -1, SQLITE_PREPARE_PERSISTENT, &count_stmt, nullptr); sqlite3_close(db); // 随后打开数据库、启动事务并执行预处理语句 sqlite3_open(filename, &db); sqlite3_exec(db, "BEGIN TRANSACTION", nullptr, nullptr, &err); sqlite3_exec(db, "INSERT INTO names (name) VALUES ('John')", nullptr, nullptr, &err); sqlite3_step(count_stmt); int count = sqlite3_column_int(count_stmt, 0); sqlite3_close(db); REQUIRE(count == 1); // 断言失败,因为事务未提交,且语句和事务不在同一连接
同连接初始化的情况(断言通过)
如果预处理语句和事务在同一个连接中创建,查询结果会包含该连接内未提交的事务变更:
// 打开数据库、预处理语句、启动事务并查询 sqlite3* db = nullptr; sqlite3_open(filename, &db); sqlite3_stmt* count_stmt = nullptr; sqlite3_prepare_v3(db, "SELECT count(*) FROM names", -1, SQLITE_PREPARE_PERSISTENT, &count_stmt, nullptr); sqlite3_exec(db, "BEGIN TRANSACTION", nullptr, nullptr, &err); sqlite3_exec(db, "INSERT INTO names (name) VALUES ('John')", nullptr, nullptr, &err); sqlite3_step(count_stmt); int count = sqlite3_column_int(count_stmt, 0); sqlite3_close(db); REQUIRE(count == 1); // 断言通过,尽管事务尚未提交
核心原因
SQLite的事务、预处理语句都是与数据库连接强绑定的:
- 预处理语句创建时会关联当前连接的上下文,包括数据快照、事务状态等。跨连接复用语句时,它无法识别新连接的事务变更,只会基于原连接的视图执行查询。
- 同一连接内的所有操作共享同一个事务上下文,预处理语句能实时看到该连接内未提交的修改,这是SQLite基于连接的事务隔离机制决定的。
内容的提问来源于stack exchange,提问作者Lucian Thorr
相关产品推荐
相关产品推荐

