Description
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