Skip to content

Watson DB2 (Connection Pool) #131

Description

@uniquejava

Db2 on cloud(先前叫dashDB), 注册需要credit card

Db2 warehouse, 可以免费注册, 以此为例, 它提供了各种编程语言的API, NODE的还是那个叫ibm_db的

提供了JDBC URL, 但是密码使用的placeholder. 需要点左边的credentials, 创建一个credential 然后从json格式的一个文件中找到密码部分.

可以用DBVisualizer连上去, 并可以建表和建SEQ.

Sybase Power Designer可以建Physical Data Model (PDM) 然后生成对应的SQL

Db2 warehouse提供的UI只能建表, 找不到建sequence的地方.

node-ibm_db

node-ibm_db是ibm db2的node版驱动. 安装npm install ibm_db --save,
安装过程要下载好几十M的clidriver安装包, 并且因为墙的原因可能会经常安装失败(下载的压缩包格式损坏)
官方的安装文档提供了不用重复下载clidriver的办法, 如果你之前有在其它项目已经用npm安装过ibm_db , 执行如下命令可以秒安装:

export IBM_DB_HOME=/Users/cyper/xxxx/ibm_db/installer/clidriver
npm install ibm_db@2.0.0 --save

也可以使用yarn安装: yarn add ibm_db

20170929: 今天在新项目安装ibm_db报错:

gyp: Call to 'node -e "require('nan')"' returned exit status 0 while in binding.gyp. while trying to load binding.gyp
gyp ERR! configure error 
gyp ERR! stack Error: `gyp` failed with exit code: 1
gyp ERR! stack     at ChildProcess.onCpExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:305:16)
gyp ERR! stack     at emitTwo (events.js:106:13)
gyp ERR! node-gyp -v v3.4.0

换成yarn的时候有如下提示

Agreeing to the Xcode/iOS license requires admin privileges, please run “sudo xcodebuild -license” and then retry this command.

gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 69
gyp ERR! stack     at ChildProcess.onExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:276:23)
gyp ERR! stack     at emitTwo (events.js:106:13)
gyp ERR! stack     at ChildProcess.emit (events.js:191:7)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:219:12)

NM的, 原来macOS自动更新了我的Xcode至9.0, 我得打开xcode同意一下新的条款. WTF

connection pool

从官方docs中找到了一些关于pool的文档, https://github.com/ibmdb/node-ibm_db#PoolAPIs
文档上关于init方法, 有如下示例代码

var ret = pool.init(5, connStr);
if(ret != true)
{
    console.log(ret);
    return false;
}

pool.open(connStr, function(err, db) { ...

一开始没怎么看明白, 比如init方法为什么没有callback, 要是出错了怎么知道(ret != true呗), 那出错的具体原因在哪? debug了一下源代码, :

原来init是一个阻塞方法, 内部会循环调用Database.openSync(...)初始化连接, 并将connection放在一个内部数组里.

init方法的返回值(示例中的ret)要么为true(表示pool初始化成功), 要么是一个Error Object. (出错的堆栈信息全在里面)

最后要注意的是连接bluemix上的db2, 需要在connectionString最后拼上Security=SSL

据此我设计了自己的db2 pool工具类 db2.js, 如下

var format = require('string-format');
var ibm_db = require('ibm_db');
var pool = new ibm_db.Pool;
var cn = null;

module.exports.initPool = initPool;
module.exports.ping = ping;
module.exports.open = open;
module.exports.close = close;
module.exports.closePool = closePool;

function initPool(db2_config, cb) {

  cn = format('DATABASE={db};HOSTNAME={host};PORT={port};PROTOCOL=TCPIP;UID={user};PWD={pass};Security=SSL', db2_config);

  // set to true then db2 driver will print debug logs.
  ibm_db.debug(!!db2_config.debug);

  pool.setMaxPoolSize(db2_config.maxPoolSize || 10);

  console.log('initializing pool, please wait ...');

  var result = pool.init(db2_config.poolSize || 1, cn);

  if (result != true) {
    return cb && cb(result);

  } else {
    console.log('pool initialized(' + db2_config.poolSize + ')');
    cb && cb(null);
  }

}

function ping() {
  console.log('ping db2 server.');

  open(function (err, conn) {
    if (err) return console.log(err);

    var rows = conn.querySync('select 1 from sysibm.sysdummy1');
    console.log(rows);

    close(conn);
  });

}


function open(cb) {
  pool.open(cn, function (err, conn) {
    if (err) {
      return cb(err);
    }

    console.log('get one connection');

    cb(null, conn);
  });
}

function close(rs, stmt, conn, cb) {

  // overload close, now we can use close(conn) | close(conn, cb) | close(rs, stmt, conn) | close(rs, stmt, conn, cb)
  if (arguments.length > 2) {
    rs && rs.closeSync();
    stmt && stmt.closeSync();

  } else {
    conn = rs;
    cb = stmt;
  }

  conn && conn.close(function () {
    console.log('connection released to pool.');
    cb && cb();
  });
}

function closePool(cb) {
  pool.close(function () {
    console.log('all connections in the pool are closed');
    cb && cb();
  });
}

我在./bin/www初始化日志组件log4js就立即初始化db2 pool, 这样如果有任何出错的日志, 会记录到日志文件, 并且如果db2 pool 初始化失败, 则直接退出app. 如果process.exit(1) 打印出来的NPM ERR吓着你, 可以用process.exit(0) 😄

// init db2 connection pool
db2.initPool(db2_config, function (err) {
  if (err) {
    console.error(err);

    log4js.shutdown();

    process.exit(1);
  } else {
    db2.ping();
  }
});

// express启动失败时的处理
    case 'EADDRINUSE':
      logger.error(bind + ' is already in use');

      db2.closePool(function () {
        log4js.shutdown();
      });

      process.exit(1);

启动时的日志如下.

[2017-09-19 14:57:55.227 INFO] env= development
[2017-09-19 14:57:55.230 INFO] node-ibm_db logs disabled.
[2017-09-19 14:57:58.876 INFO] pool initialized
[2017-09-19 14:57:58.877 INFO] ping db2 server.
[2017-09-19 14:57:58.877 INFO] get one connection
[2017-09-19 14:57:59.503 INFO] [ { '1': 1 } ]
[2017-09-19 14:57:59.505 INFO] connection released to pool.
[2017-09-19 14:57:59.509 INFO] Listening on port 3000



References

https://www.ibm.com/support/knowledgecenter/en/SS6NHC/com.ibm.swg.im.dashdb.doc/learn_how/designdb_create_new.html

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions