我正在玩node-sqlite3 package并遇到了一个奇怪的情况。 这个简单的脚本有一个简单的逻辑:查找表是否存在,是否清空,如果没有 - 创建它。
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('guy.sqlite'); //':memory:'
var tableExists = false;
db.serialize(function() {
db.get("SELECT name FROM sqlite_master WHERE type='table' AND name='lorem'", function(error, row) {
tableExists = (row != undefined);
console.log("xxxxx " +tableExists);
});
console.log("yyyyy " +tableExists);
if (tableExists) {
console.log("table exists. cleaning existing records");
db.run("DELETE FROM lorem", function(error) {
if (error)
console.log(error);
});
}
else {
console.log("creating table")
db.run("CREATE TABLE lorem (info TEXT)", function(error) {
if (error.message.indexOf("already exists") != -1) {
console.log(error);
}
});
}
});
db.close();
但我得到的结果是:
yyyyy false
creating table
xxxxx true
{ stack: [Getter/Setter],
arguments: undefined,
type: undefined,
message: 'SQLITE_ERROR: table lorem already exists',
errno: 1,
code: 'SQLITE_ERROR' }
根据serialize command documentation,这些查询应该按顺序运行。很明显,tableExists
(标有'yyy')的评估发生在设置值(标有'xxx')之前,导致尝试重新创建现有表。
我可以处理错误,但我想知道是什么导致这种情况以及如何在将来避免这种行为。
一如既往,谢谢你的时间。
盖
答案 0 :(得分:1)
node.js在异步模式下工作,但是你的代码是混合同步和异步形式的一种奇怪的形式。
select之后的完整代码应该在回调中,当你的实际代码没有达到你想要的效果时,tableexists将没有你喜欢的值。
学习爱好node.js的异步模型;)
答案 1 :(得分:1)
文档中的示例2直接解释了您的问题。 tableExists变量在第一次运行时将为false,而SELECT函数仅在事件循环中排队,并且在serialize()中的代码完成之后才会运行。解决方案是将if(tableExists)
代码放在回调中以进行SELECT。这违背了使用序列化的目的,但这就是它的工作原理。写入值很好,因为它们将按照调用顺序排队,但需要通过I / O响应的东西需要回调,因此异步运行。
此外,SQLITE_MISUSE
错误来自于在脚本末尾调用db.close()但在异步回调之外调用的事实。即使它位于脚本的末尾,任何异步内容都会放入队列中,直到 当前函数完成后才会被调用。