我在创建和填充表后立即执行SQL语句时遇到问题。
我认为记录不存在,因为创建查询没有及时完成。
如果我为clean
标志(在createDatabaseFromSQL
中)传递false
,经过几次尝试后,
我得到了预期的结果:
$ node ./setup.js
CREATE database
Executing: DROP TABLE IF EXISTS `accounts`
Executing: CREATE TABLE IF NOT EXISTS `accounts` ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `username` VARCHAR(50) NOT NULL, `password` VARCHAR(255) NOT NULL, `email` VARCHAR(100) NOT NULL )
Executing: INSERT INTO `accounts` (`username`, `password`, `email`) VALUES ('admin', 'admin', 'admin@admin.com'), ('test', 'test', 'test@test.com')
FETCH test account
Connected to the 'auth' database.
Connected to the 'auth' database.
true
Close the 'auth' database connection.
Close the 'auth' database connection.
如果强制清除,选择将失败,因为accounts
表不存在。
$ node ./setup.js
CREATE database
Executing: DROP TABLE IF EXISTS `accounts`
Executing: CREATE TABLE IF NOT EXISTS `accounts` ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, `username` VARCHAR(50) NOT NULL, `password` VARCHAR(255) NOT NULL, `email` VARCHAR(100) NOT NULL )
Executing: INSERT INTO `accounts` (`username`, `password`, `email`) VALUES ('admin', 'admin', 'admin@admin.com'), ('test', 'test', 'test@test.com')
FETCH test account
Connected to the 'auth' database.
Connected to the 'auth' database.
node:internal/process/esm_loader:97
internalBinding('errors').triggerUncaughtException(
^
[Error: SQLITE_ERROR: no such table: accounts] {
errno: 1,
code: 'SQLITE_ERROR'
}
Node.js v18.14.0
文件
以下是相关文件。
设置. js
import { createDatabaseFromSql, executeQuery } from "./query-utils.js";
console.log("CREATE database");
await createDatabaseFromSql("auth", "./setup.sql", true);
console.log("FETCH test account");
const row = await executeQuery(
"auth",
"SELECT * FROM `accounts` where `username` = ?",
["test"]
);
console.log(row?.id === 2);
查询实用程序. js
import fs from "fs";
import sqlite3 from "sqlite3";
const SQL_DEBUG = true;
const loadSql = (filename, delimiter = ";") =>
fs
.readFileSync(filename)
.toString()
.replace(/(\r\n|\n|\r)/gm, " ")
.replace(/\s+/g, " ")
.split(delimiter)
.map((statement) => statement.trim())
.filter((statement) => statement.length);
const executeSerializedQueries = async (databaseName, callback) => {
let db;
try {
db = new sqlite3.Database(`./${databaseName}.db`, (err) => {
if (err) console.error(err.message);
console.log(`Connected to the '${databaseName}' database.`);
});
db.serialize(() => {
callback(db);
});
} catch (e) {
throw Error(e);
} finally {
if (db) {
db.close((err) => {
if (err) console.error(err.message);
console.log(`Close the '${databaseName}' database connection.`);
});
}
}
};
const createDatabaseFromSql = async (databaseName, sqlFilename, clean) =>
new Promise((resolve, reject) => {
if (clean) {
fs.rmSync(`./${databaseName}.db`, { force: true }); // Remove existing
}
try {
executeSerializedQueries(databaseName, (db) => {
loadSql(sqlFilename).forEach((statement) => {
if (SQL_DEBUG) {
console.log("Executing:", statement);
}
db.run(statement);
});
resolve();
});
} catch (e) {
reject(e);
}
});
const executeQuery = async (databaseName, query, params = []) =>
new Promise((resolve, reject) => {
try {
executeSerializedQueries(databaseName, (db) => {
db.get(query, params, (error, row) => {
if (error) reject(error);
else resolve(row);
});
});
} catch (e) {
reject(e);
}
});
const executeQueryAll = async (databaseName, query, params = []) =>
new Promise((resolve, reject) => {
try {
executeSerializedQueries(databaseName, (db) => {
db.all(query, params, (error, rows) => {
if (error) reject(error);
else resolve(rows);
});
});
} catch (e) {
reject(e);
}
});
export {
createDatabaseFromSql,
executeSerializedQueries,
executeQuery,
executeQueryAll,
loadSql,
};
设置. sql
DROP TABLE IF EXISTS `accounts`;
CREATE TABLE IF NOT EXISTS `accounts` (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`username` VARCHAR(50) NOT NULL,
`password` VARCHAR(255) NOT NULL,
`email` VARCHAR(100) NOT NULL
);
INSERT INTO `accounts` (`username`, `password`, `email`)
VALUES ('admin', 'admin', 'admin@admin.com'),
('test', 'test', 'test@test.com');
软件包. json
{
"dependencies": {
"sqlite3": "^5.1.4"
}
}
2条答案
按热度按时间qacovj5a1#
db.serialize
很难在promise/async代码中使用,因为它不遵循“完成后运行此回调”的标准回调约定。它也只序列化sqlite的查询,不影响nodejs中的控制流,将立即继续使用更多代码。基本上,
db.serialize
中的最终查询通常是在您希望解析承诺时,类似于:当传递包含在其他地方构造的数据库命令的函数时,这也很难概括,如示例代码中的。
幸运的是,promise提供了自己的控制流,所以我们可以暂时不考虑serialize。
转换成承诺
下面是一个承诺的“打开数据库”函数
回调中的
err
被拒绝,value
在回调中被解析,promise从函数返回。函数只有一个用途,即把回调操作转换为promise。你可以在一个承诺中 Package 更大的回调链,但是承诺存在的原因是为了消除管理大型异步回调链的心理负担和边缘情况。同样的基本规则适用,来自 all 回调的
err
应该reject
或被处理。然后回调链中的最后一个函数应该resolve
一个值,如果你想等待所有事情完成。这不是一个通用的解决方案,如OP,但一个简单的promised版本的安装程序,然后可以。
数据库API现在可以通过承诺函数访问,因此所有函数都不需要重复地用承诺来 Package 回调。
串行查询可以在for循环中等待(顺序类似于db.serialize),但nodejs的控制流在查询完成之前不会继续,所有回调错误都由promised函数处理。
fquxozlt2#
我最终选择了better-sqlite3。这个库不依赖于
async
或Promise
逻辑。设置. js
查询实用程序. js