`db.serialize`如何在`node-sqlite3`中工作

时间:2017-01-31 04:38:11

标签: node.js database sqlite node-sqlite3

最近我学习使用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();

2 个答案:

答案 0 :(得分:18)

serialize()函数中的每个命令都保证在下一个函数开始之前完成执行。

在您的示例中,CREATE TABLE将在INSERT运行之前完成。如果您没有使用serialize(),那么CREATE TABLEINSERT语句将并行运行。它们会一个接一个地快速启动,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足够聪明,不会这样做! :)