Node.jsからMariaDBを操作
以前Node.jsにクローラを設定して、天気予報を取得しました。
今回はそこで取得した天気予報をデータベースに保存しておきたいと考えたので、Node.js経由でMariaDBデータベースに保存します。
Node.jsの初期設定方法はリンク先の記事で紹介しています。ここではパッケージは、mysqlをインストールするところから始めます。
インストールと使い方
まずは既存のNode.jsのプロジェクトにmysqlをインストールします。もし、新規プロジェクトを作成するのなら事前に「nmp init -y」コマンドを実行しておいてください。
基本的な使い方は先のnpmjsのページから引用して紹介します。
conectionオブジェクトを次の引数を使って作成します。hostにサーバーのアドレス、userに接続ユーザー名、passwordにパスワード、databaseに接続するデータベース名をセットします。他に設定可能な値としてcharset等があります。
connectionオブジェクトは、connect()で接続、end()で切断、query(SQL,function)でSQLの実行をします。queryの第1引数にはSQL文、第2引数にはSQL実行後の関数を渡します。
プレースホルダ(?)を使う場合は、引数がひとつ増え、第2引数にはバインドする値の配列を渡します。配列にはプレースホルダの順に値を入れます。関数を渡す場所はひとつ繰り下がり第3引数になります。
sample.js
var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'me', password : 'secret', database : 'my_db' }); connection.connect(); connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) { if (error) throw error; console.log('The solution is: ', results[0].solution); }); connection.end();
resultsに行が返り、カラム名がプロパティになっています。ここでは一番最初(インデックスが0)の行の、solutionカラムの値をconsole.logで表示しています。
SQL文中では、カラム名の文字の大小は区別されませんが、resultsではカラム名が大文字なら大文字、小文字なら小文字で指定しないと取得できません。
SQL文内のテーブル名に関しては、MySQL側のルールで、テーブル名は大文字小文字を区別するOSで動くサーバーの場合は一致させる必要があり、区別しないOSで動くサーバーの場合はどちらでもかまいません。
トランザクションにも対応しているようで、こちらも公式ページに使い方が次のように掲載されていました。
注意が必要なのはbeginTransactionやquery関数はasync(非同期)だという点です。この関数の外側に続けてconnection.end()と書いてしまうとトランザクションやクエリの途中でコネクションが切断されてしまい「Error: Cannot enqueue Query after invoking quit.」のエラーがでます。
connecion.end()は、エラートラップ時かcommitのコールバック関数内(参考スクリプト内ではconsole.log('success!');の場所です)で実行しましょう。
transaction.js
... connection.beginTransaction(function(err) { if (err) { throw err; } connection.query('INSERT INTO posts SET title=?', title, function (error, results, fields) { if (error) { return connection.rollback(function() { throw error; }); } var log = 'Post ' + results.insertId + ' added'; connection.query('INSERT INTO log SET data=?', log, function (error, results, fields) { if (error) { return connection.rollback(function() { throw error; }); } connection.commit(function(err) { if (err) { return connection.rollback(function() { throw err; }); } console.log('success!'); }); }); }); }); ...
fields
実行時に渡すコールバック関数にたびたび含まれるfieldsですが、これにはカラムの情報が入ってきます。
ひとつのカラムはひとつのFieldPacketで表現され、SQLで指定したカラムの数だけFieldPacketは存在します。fieldsはそのFieldPacketの配列です。なので、結果の列数を取得したければfields.lengthで取得できます。
FieldPacketオブジェクトは次のプロパティをもちます。
- catalog
- db
データベース名
- table
SQL文で指定したカラムが所属するテーブル名
- orgTable
オリジナルのテーブル名
- name
SQL文で指定したカラム名
- orgName
オリジナルのカラム名
- charsetNr
- length
全体のカラム長。たとえばdecimal(8,2)の時は10が入り、UTF-8のchar(1)の時は3が入ります
- type
カラムのタイプが数値で入ります。decimalは246、charは254です
- flags
- decimals
decimal指定時の小数点以下のサイズです。decimal(8,2)の時は2が入ります
- default
- zeroFill
- protocol41
筆者が実際に作成したコード
実際に作成したコードは次のようになりました。
updatedb.js
let mysql = require('mysql');
let dbRows = getDbRows();//更新用のデータが入った配列を取得します。
//複数行を処理する為に、成功時に再帰呼び出しをします。
function insDbRowTask (intIndex, connection) {
if (intIndex < dbRows.length) {
connection.query('INSERT INTO WEATHER_TABLE VALUES(?,?,?,?,?)',dbRows[intIndex],function (error, results, fields){
if (error) { throw error; }
insDbRowTask(intIndex+1,connection);
});
} else {
//最終処理(commit)
connection.commit(function(err) {
if (err) {
//コミットエラー;
throw err;
} else {
connection.end();
}
});
}
}
function updateDb() {
//mysqlオープン
let connection = mysql.createConnection({
host : 'localhost',
user : 'admin',
password : 'admin',
database : 'test'
});
connection.connect();
try {
connection.beginTransaction(function(err) {
if (err) { throw err; }
insDbRowTask(0, connection);
});
} catch(e) {
connection.rollback(function(){
connection.end();
});
}
}