Node.jsでSQLiteを使う

sqlite3を使うとNode.jsからSQLiteを操作できます。

バージョン

  • sqlite3 – 5.0.10

インストール

npm install sqlite3

使い方

const sqlite3 = require('sqlite3').verbose();

// データベースに接続する.
let db = new sqlite3.Database(<データベースファイルのパス>);

db.all('<SQL文>', [パラメータ], (err, rows) => {
    if (err) {
        // エラー発生時.
        return;
    }
    // 取得データ rows に対する処理.
});

// データベースの切断.
db.close();

パラメータ渡しの例

パラメータ数と配列の要素数を同じにします。パラメータ無しの場合は[]を指定、または省略できます。

db.all('SELECT * FROM HISTORIES ORDER BY registered_at DESC LIMIT ?', [10], (err, rows) => {});

SELECT処理

SELECTには次の3つのメソッドが利用できます。

  • db.get() – 抽出結果の先頭1行のみを返します
  • db.all() – 全ての抽出結果を返します
  • db.each() – 抽出結果を順次返します
    db.each("SELECT * FROM HISTORIES", (err, row) => {
        // 抽出数分実行される.
        console.log(row);
    });
    

INSERT処理など

db.run()で非同期にSQL文を実行できます。

db.run('INSERT INTO HISTORIES (type, status) VALUES (?,?)', [1, 200]);

発行したSQL文を順番に実行したい場合はdb.serialize()を使います。

db.serialize(() => {
    db.run('CREATE TABLE SAMPLE(type, status)');
    db.run('INSERT INTO SAMPLE (type, status) VALUES (?,?)', [1, 200]);
    db.all('SELECT * FROM SAMPLE', (err, rows) => {
        console.log(rows);
    });
});

prepare

複数データの登録を行う場合は、db.prepare()が利用できます。

db.serialize(() => {
    let statement = db.prepare('INSERT INTO SAMPLE (type, status) VALUES (?,?)');
    statement.run([1, 100]);
    statement.run([1, 200]);
    statement.run([2, 200]);
    statement.run([2, 400]);
    statement.finalize();
});

db.all('SELECT * FROM SAMPLE', (err, rows) => {
    console.log(rows);
});

nexeでexe化したときに次のエラーが出る場合の対処方法

nexeを使ってNode.jsプロジェクトをexe化して実行すると、次のようなエラーが発生しました。その時の対処方法。

Node v14

Error: The specified module could not be found.
\\?\C:\<プロジェクト>\node_modules\sqlite3\lib\binding\napi-v6-win32-unknown-x64\node_sqlite3.node

Node v12

Error: Cannot find module 'C:\<プロジェクト>\node_modules\sqlite3\lib\binding\napi-v3-win32-unknown-x64\node_sqlite3.node'

対処方法

  1. \node_modules\sqlite3\lib\binding\napi-v6-win32-unknown-x64ディレクトリをカレントディレクトリにコピーする
  2. \node_modules\sqlite3\package.jsonの次の箇所を書き換える
    • 変更前
      "binary": {
      "module_path": "./lib/binding/napi-v{napi_build_version}-{platform}-{libc}-{arch}",
      },
      
    • 変更後
      "binary": {
      "module_path": "../../napi-v{napi_build_version}-{platform}-{libc}-{arch}",
      },
      

実行時の構成

\napi-v6-win32-unknown-x64
  node_sqlite3.node
xxxxx.exe

ディレクトリ内のnode_sqlite3.nodeのみをカレントディレクトリにコピーしてパスを指定してもうまく動かないのでディレクトリごとコピーします。

Promise で返す方法

結果をpromiseで返却するサンプルです。selectHistoriesAsync()呼び出し側はawaitで結果を待つことができます。

selectHistoriesAsync() {
    return new Promise((resolve, reject) => {
        let db = new sqlite3.Database(<データベースファイルのパス>);
        db.all('SELECT * FROM HISTORIES', [], (err, rows) => {
            if (err) {
                reject('error reason');
                return;
            } 
            resolve(rows);
        });
        db.close();
    });
}

エラー対処方法

クエリ(SQL文)実行結果のコールバック内で更に別のクエリを実行時に次のようなエラーが発生することがあります。

[Error: SQLITE_MISUSE: Database handle is closed] {
  errno: 21,
  code: 'SQLITE_MISUSE'
}

これはdb.close()が先に動作するためです。
db.close()以前に発行済みのクエリは実行されてからデータベースのクローズが行われますが、コールバック内のクエリは未だ発行されていないためエラーが発生します。
これを回避するためには、コールバック内のクエリを実行してから、db.close()をコールするようにします。

このエントリーをはてなブックマークに追加
にほんブログ村 IT技術ブログへ

関連コンテンツ

スポンサードリンク

コメント

メールアドレスが公開されることはありません。