Oracle 数据库不会刷新数据。

5
我正在使用Node.js开发一个简单的服务。它能够接收上传的文件,将其存储在磁盘上,并在Oracle表中记录一些元数据。我使用了“db-oracle”包以及连接池来进行开发,按照这篇文章:http://nodejsdb.org/2011/05/connection-pooling-node-db-with-generic-pool/ 的指示。
然而,我注意到插入的数据仅在连接池通过调用其“disconnect()”方法关闭空闲连接后才会发送至Oracle数据库。
有没有办法在向客户端发送“OK”信号之前刷新数据?现在的工作方式是,我的WebService或Oracle本身崩溃可能导致数据丢失,而我的服务的客户端将不会知道这件事。我实际上通过在上传一些内容后杀死我的应用程序进程测试了这一点,结果数据确实丢失了。
以下是代码的简化版本:
var express = require('express');
var app = module.exports = express.createServer();

app.post('/upload', handleUpload);

app.listen(4001, function(){
  console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
});

function handleUpload(req, res) {
  res.contentType('application/xml');

  var buf = '';
  req.on('data', function(chunk) { buf += chunk; });
  req.on('end', function() {
    saveUpload(req, res, buf);
  });
}

function saveUpload(req, res, buf) {
  if (buf.length == 0)
    return sendError(res, 'No data supplied', 422);

  var payload = new Buffer(buf, 'base64');

  files.save(payload, function(err, savedFile) {
    if (err)
      return sendError(res, 'Error while saving', 500);

    var obj = { ip: req.connection.remoteAddress, location: savedFile.path,
                created_at: new Date(), updated_at: new Date() };

    var fields = ['IP', 'LOCATION', 'CREATED_AT', 'UPDATED_AT'];
    var values = fields.map(function(v) { return obj[v.toLowerCase()] });

    pool.acquire(function(err, conn) {
      if (err)
        return sendError(res, err, 500);

      var q = conn.query().insert('FILES', fields, values);

      q.execute(function(err, result) {
        pool.release(conn);

        if (err)
          return sendError(res, err, 500);

        if (result.affected < 1)
          return sendError(res, 'Error saving the record', 500);

        // The next statement sends the final result to the client.
        // However, the new record was not yet flushed to the database.
        res.end('<ok />');
      });
    });
  });
}

function sendError(res, err, code) {
  console.log(err);
  res.send('<error>' + err + '</error>', code || 500);
}

作为一种解决方法,我尝试实现了一个虚假的连接池并释放了所有已获取的连接,但现在我的应用程序显示以下信息而终止:pure virtual method calledAbort trap: 6 这是虚假连接池的代码:
var fakePool = {
  acquire: function(callback) {
    new oracle.Database(config.database).connect(function(err, server) {
      callback(err, this);
    });
  },
  release: function(conn) {
    conn.disconnect();
  }
};

为了明确起见,我不关心虚假连接池器,这只是一个肮脏的解决方法。我希望能够在向客户端发送“OK”之前将数据刷新到Oracle。

顺便说一下,我还在他们的Github上开了一个工单:https://github.com/mariano/node-db-oracle/issues/38


我在代码中没有看到任何提交... - user330315
是的,据我所知,db-oraclenode-db包都没有暴露任何方法。我已经深入研究了它们的文档和源代码,没有找到任何明确执行提交的方法。不过,在OCCI文档中我找到了一个commit方法。也许我需要fork这个项目并暴露出提交方法? - Fábio Batista
这些软件包是否依赖于(呃!)自动提交行为? - Bob Jarvis - Слава Україні
2个回答

6

显然,您忘记提交事务了。

node-db不需要公开提交API,因为在大多数RDBMS(包括Oracle)中,COMMIT是一个有效的查询。由于该软件包允许执行任意查询,因此提交/回滚应该使用简单的execute()完成。

代码应该更改如下:

pool.acquire(function(err, conn) {
  if (err)
    return sendError(res, err, 500);

  var q = conn.query().insert('FILES', fields, values);
  q.execute(function(err, result) {

    if (err || result.affected < 1 ) {
       pool.release(conn);
       return sendError(res, err, 500);
    }

    conn.query().execute("commit", function(err,result) {
      if (err) {
        pool.release(conn);
        return sendError(res, err, 500);
      }
      res.end('<ok />');
      pool.release(conn);
    });
  });
});

1

谢谢,@npe...我也会尝试使用node-oracle。不幸的是,它没有与node-db集成。 - Fábio Batista

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接