Skip to content

Watson DB2 (Connection Pool) #131

Open
@uniquejava

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

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