Node.js SQLite异步事务

我使用 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
);

你也可以运行the full example.

问题是,在开始或插入后的异步暂停期间,可以启动一些带有插入或更新查询的其他代码.然后在事务中运行此额外查询.提交事务时,这不是问题.但是,如果事务被回滚,则此额外查询所做的更改也会回滚.我们只是不可预测地丢失数据而没有任何错误消息.

我想到了这个问题,我认为一个解决方案是创建一个包装类,以确保:

>只有一个事务同时运行.
>当事务运行时,只执行属于事务的查询.
>所有额外查询在当前事务完成后排队并执行.
>当一个事件已经运行时,所有尝试启动事务也将排队.

但这听起来像是太复杂的解决方案.有更好的方法吗?你是如何处理这个问题的?

解决方法

首先,我想说我没有使用sqlite的经验.我的回答是基于对node-sqlite3快速研究.

您的代码IMHO的最大问题是您尝试从不同位置写入数据库.据我了解sqlite,您无法控制Postgresql中的不同并行“连接”,因此您可能需要将所有与DB的通信包装起来.我修改了你的例子以使用always insert包装器.这是修改后的功能

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();
    });
  });
}

使用以下代码调用函数

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++]);
  }

  ...

我做了以下更改:

>添加了cmds参数,为简单起见,我将其添加为最后一个参数,但回调应该是最后一个(cmds是插入值的数组,在最终实现中它应该是一个sql命令数组)
>将db.exec更改为db.run(应该更快)
>添加了db.serialize以序列化事务内的请求
> BEGIN命令的ommited回调
>省略幻灯片和一些下划线

您的测试实现现在对我来说很好.

相关文章

这篇文章主要介绍“基于nodejs的ssh2怎么实现自动化部署”的...
本文小编为大家详细介绍“nodejs怎么实现目录不存在自动创建...
这篇“如何把nodejs数据传到前端”文章的知识点大部分人都不...
本文小编为大家详细介绍“nodejs如何实现定时删除文件”,内...
这篇文章主要讲解了“nodejs安装模块卡住不动怎么解决”,文...
今天小编给大家分享一下如何检测nodejs有没有安装成功的相关...