最近我学习使用node和node-sqlite3来操作sqlite3,这是一个示例。
var sqlite3 = require('sqlite3');
var db = new sqlite3.Database(':memory:');
db.serialize(function() {
db.run("CREATE TABLE test(info TEXT)");
db.run("INSERT INTO test (info) VALUES ('info1')");
})
db.close();
文档说db.serialized
用于确保SQL行按顺序执行,但我很困惑,为什么在没有db.serialize
的情况下它们不能按顺序执行,毕竟它们会从事件队列中拉出并按顺序执行?它在这里如何运作?
如果只有一个sql要执行,没有db.serialize
运行它是否安全?如下所示?
var sqlite3 = require('sqlite3');
var db = new sqlite3.Database(':memory:');
db.run("CREATE TABLE test(info TEXT)");
db.close();
答案 0 :(得分:18)
serialize()
函数中的每个命令都保证在下一个函数开始之前完成执行。
在您的示例中,CREATE TABLE
将在INSERT
运行之前完成。如果您没有使用serialize()
,那么CREATE TABLE
和INSERT
语句将并行运行。它们会一个接一个地快速启动,INSERT
实际上可能在创建表之前完成,这使您在尝试将数据插入到不存在的表中时出错。
这称为竞争条件,因为每次运行程序时,您都可能获得不同的赢家。如果CREATE TABLE
赢得比赛,那么该计划将正常运作。但如果INSERT
赢得比赛,程序将因错误而中断。由于您无法控制谁赢得比赛,serialize()
将停止INSERT
甚至开始直到CREATE TABLE
到达终点,确保您每次都获得相同的结果。
在第二个只有一个语句的例子中,仍然需要serialize()
。这是因为run()
启动SQL查询但立即返回,使查询在后台运行。由于您的下一个命令是close()
数据库的一个命令,因此您将在查询仍在运行时将其剪切掉。
由于serialize()
在最后一个内部查询完成之前不会返回,因此使用它将暂停close()
,直到查询完成。
如果您使用的是其他类型的查询(例如,响应用户点击网页上的按钮,数据库在调用之间保持打开状态),那么您可能不需要serialize()
。它取决于每个查询后面的代码是否需要在它完成之前的查询。
在决定是否使用serialize()
时,将任何非序列化查询视为已注释掉,然后查看代码是否仍然有用可能会有所帮助。在上面的第一个示例中,删除CREATE TABLE
命令会破坏以下INSERT
语句(因为那时没有要插入的表),因此需要序列化这些语句。但是如果你有两个CREATE TABLE
命令,那么删除一个不会影响另一个,所以这两个命令不必序列化。
(此提示不适用于close()
- 经验法则是,只有在所有内容都运行完毕后才会调用close()
。)
答案 1 :(得分:1)
我在SQLite documentation中找到了这个:
Database#close方法将始终以独占模式运行,这意味着 它等待直到所有先前的查询都已完成并且node-sqlite3 关闭即将结束时,将不会运行任何其他查询。
因此,看来您最后一个问题的答案是是。如果只有一个查询要运行,则不需要序列化功能。您无需担心数据库在查询完成之前就被关闭,因为SQLite足够聪明,不会这样做! :)