Str*_*rix 5 sqlite asynchronous transactions node.js
我正在使用node-sqlite3,但我确信这个问题也出现在另一个数据库库中。我在混合事务和异步代码的代码中发现了一个错误。
function insertData(arrayWithData, callback) {
// start a transaction
db.run("BEGIN", function() {
// do multiple inserts
slide.asyncMap(
arrayWithData,
function(cb) {
db.run("INSERT ...", cb);
},
function() {
// all done
db.run("COMMIT");
}
);
});
}
// some other insert
setInterval(
function() { db.run("INSERT ...", cb); },
100
);
Run Code Online (Sandbox Code Playgroud)
您还可以运行完整的示例。
问题是,在or之后的异步暂停期间,可以启动带有insert
或查询的其他一些代码。然后这个额外的查询在事务中运行。当事务提交时这不是问题。但是,如果事务回滚,则此额外查询所做的更改也会回滚。哎呀,我们刚刚意外地丢失了数据,但没有任何错误消息。update
begin
insert
我考虑过这个问题,我认为一个解决方案是创建一个包装类,以确保:
但这听起来像是太复杂的解决方案。有更好的方法吗?你如何处理这个问题?
首先,我想声明我没有使用 SQLite 的经验。我的回答是基于对 的快速研究node-sqlite3
。
恕我直言,您的代码最大的问题是您尝试从不同的位置写入数据库。据我了解 SQLite,您无法像在 PostgreSQL 中那样控制不同的并行“连接”,因此您可能需要包装与 DB 的所有通信。我修改了您的示例以使用始终insertData
包装器。这是修改后的函数:
function insertData(callback, cmds) {
// start a transaction
db.serialize(function() {
db.run("BEGIN;");
//console.log('insertData -> begin');
// do multiple inserts
cmds.forEach(function(item) {
db.run("INSERT INTO data (t) VALUES (?)", item, function(e) {
if (e) {
console.log('error');
// rollback here
} else {
//console.log(item);
}
});
});
// all done
//here should be commit
//console.log('insertData -> commit');
db.run("ROLLBACK;", function(e) {
return callback();
});
});
}
Run Code Online (Sandbox Code Playgroud)
使用以下代码调用函数:
init(function() {
// insert with transaction
function doTransactionInsert(e) {
if (e) return console.log(e);
setTimeout(insertData, 10, doTransactionInsert, ['all', 'your', 'base', 'are', 'belong', 'to', 'us']);
}
doTransactionInsert();
// Insert increasing integers 0, 1, 2, ...
var i=0;
function doIntegerInsert() {
//console.log('integer insert');
insertData(function(e) {
if (e) return console.log(e);
setTimeout(doIntegerInsert, 9);
}, [i++]);
}
...
Run Code Online (Sandbox Code Playgroud)
我做了以下更改:
slide
一些underscore
您的测试实现现在对我来说效果很好。