8. データベース
Node.jsからデータベースに接続する方法を学びます。SQLiteを使用して、データの作成・読み取り・更新・削除を行います。
この章で学べること
- Node.jsからデータベースに接続する方法
- データの作成(Create): INSERT文の実行
- データの読み取り(Read): SELECT文の実行
- データの更新(Update): UPDATE文の実行
- データの削除(Delete): DELETE文の実行
- データベース操作でのエラー処理方法
データベースとは?
データベースは、アプリケーションの心臓部とも言える重要な技術です。ユーザー情報、商品データ、学習進捗など、アプリケーションで扱う様々な情報を安全かつ効率的に保存・管理するために使用されます。
この章では、Node.jsからデータベースに接続し、データの登録・取得・更新・削除(CRUD操作)を行う方法を学習します。SQLiteという軽量なデータベースを使用して、実際にコードを書きながらデータベースの基本操作を身につけていきましょう。
データベース接続の流れ
Node.js からデータベースに接続する流れはどの種類のデータベースでもほぼ共通です。
- DBクライアントライブラリをインストール
- 接続情報(ホスト名・ユーザー名・パスワード・DB名など)を設定
- 接続を確立
- クエリを実行
- 結果を取得して処理
- 接続を閉じる
プロジェクトを作成しよう
まずは、プロジェクトのディレクトリを作成します。 node-database という名前で作成します。
mkdir node-database
cd node-database
次にnpm initコマンドを実行します。プロジェクト管理ファイルの package.json が作成されます。
npm init -y
次のコマンドで package.jsonにmoduleモードの設定を追加します。
npm pkg set type=module
SQLite をインストール
次のコマンドでSQLiteをインストールします。SQLite は「ファイル1つで動く軽量データベース」で、開発・学習・小規模アプリに最適です。
npm install sqlite sqlite3
SQLiteに接続
SQLiteに接続する機能を作成します。db.jsというファイルを作成して、次のコードを記入してください。
import sqlite3 from "sqlite3";
import { open } from "sqlite";
// SQLiteに接続する関数
export async function initDB() {
const db = await open({
// openで接続を確立
filename: "./database.db", // DBファイル名
driver: sqlite3.Database,
});
// usersテーブルを作成
await db.exec(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL
);
`);
return db;
}
データの登録
データベースにデータを登録しましょう。insert.jsを作成して、次のコードを入力してください。
import { initDB } from "./db.js"; // db.jsからinitDB関数をインポート
async function insertUser(name, email) {
const db = await initDB(); // DB接続を確立
try {
// データを登録
const result = await db.run(
"INSERT INTO users (name, email) VALUES (?, ?)",
[name, email]
);
console.log(`登録完了: ID = ${result.lastID}`);
} finally {
await db.close(); // 接続を閉じる
}
}
// 登録するデータ
await insertUser("Taro", "taro@example.com");
await insertUser("Hanako", "hanako@example.com");
実行してみましょう。
node insert.js
結果
登録完了: ID = 1
登録完了: ID = 2
このとき database.db が自動生成され、ユーザーデータが追加されています。
データベースの初期化について
もしデータベースを初期化したい場合は、database.dbを削除してください。
データの取得
データベースからデータを取得しましょう。read.js を作成して、次のコードを入力してください。
import { initDB } from "./db.js"; // db.jsからinitDB関数をインポート
const db = await initDB();
try {
const users = await db.all("SELECT * FROM users"); // クエリを実行
console.log(users); // 結果を表示
} finally {
await db.close(); // 接続を閉じる
}
実行
node read.js
結果
[
{ id: 1, name: 'Taro', email: 'taro@example.com' },
{ id: 2, name: 'Hanako', email: 'hanako@example.com' }
]
データの更新
データの更新をしてみましょう。update.jsを作成し、次のコードを記入してください。
import { initDB } from "./db.js"; // db.jsからinitDB関数をインポート
const db = await initDB();
try {
// 例:id=1 のユーザーの名前と年齢を更新
const userId = 1;
const newName = "Jiro";
const newEmail = "jiro@example.com";
const result = await db.run(
`UPDATE users SET name = ?, email = ? WHERE id = ?`,
[newName, newEmail, userId]
);
if (result.changes > 0) {
console.log(`ユーザーID ${userId} の情報を更新しました`);
} else {
console.log(`ユーザーID ${userId} は見つかりませんでした`);
}
} finally {
await db.close(); // 接続を閉じる
}
実行
node update.js
結果
ユーザーID 1 の情報を更新しました
データが更新されているかを確認してみましょう。
node read.js
結果
[
{ id: 1, name: 'Jiro', email: 'jiro@example.com' }, // このデータが更新されている
{ id: 2, name: 'Hanako', email: 'hanako@example.com' }
]
データの削除
データの削除をしてみましょう。delete.jsを作成し、次のコードを記入してください。
import { initDB } from "./db.js"; // db.jsからinitDB関数をインポート
const db = await initDB();
try {
// ユーザーを全て削除
const result = await db.run(`DELETE FROM users`);
if (result.changes > 0) {
console.log(`ユーザーを削除しました`);
} else {
console.log(`ユーザー削除に失敗しました`);
}
} finally {
// DB接続を閉じる
await db.close();
}
実行
node delete.js
結果
ユーザーを削除しました
データが削除されているかを確認しましょう。
node read.js
結果
[]
エラーハンドリング
データベース操作では、様々なエラーが発生する可能性があります。適切なエラーハンドリングを実装することで、アプリケーションの安定性とユーザー体験を向上させることができます。
基本的なエラーハンドリング
データベース操作では、以下のようなエラーが発生する可能性があります。
- 接続エラー: データベースサーバーに接続できない
- SQLエラー: 無効なSQL文や構文エラー
- 制約エラー: 主キー重複、外部キー制約違反など
- 権限エラー: データベースへのアクセス権限がない
エラーハンドリングの実装例
error-handling.jsを作成して、適切なエラーハンドリングを実装してみましょう。
import { initDB } from "./db.js"; // db.jsからinitDB関数をインポート
const db = await initDB();
try {
const users = await db.all("SELECT * FROM user"); // userテーブルは存在しない(正しくはusers)
console.log(users); // 結果を表示
} finally {
await db.close(); // 接続を閉じる
}
console.log("処理完了");
error-handling.jsを実行してみましょう。
node error-handling.js
結果
node:internal/modules/run_main:122
triggerUncaughtException(
^
[Error: SQLITE_ERROR: no such table: user] {
errno: 1,
code: 'SQLITE_ERROR'
}
Node.js v22.15.0
何やらエラーが発生しているようですが、システム的でわかりにくいメッセージになっています。また、処理の最後に処理完了というメッセージが表示されるはずですが、表示されていません。これは、エラーが発生した時点で処理が止まってしまうためです。
上記のコードはエラーハンドリングが適切に実施されておらず、次の問題があります。
- エラーメッセージがわかりにくい
- 処理が途中で止まってしまう
上記の問題を解決するために、エラーハンドリングを改善しましょう。catch構文を追加して、エラーハンドリングを行います。
error-handling.js を次のような修正します。
import { initDB } from "./db.js";
const db = await initDB();
try {
const users = await db.all("SELECT * FROM user");
console.log(users);
} catch (error) { // エラーハンドリングを追加
console.error("エラーが発生しました:", error.message); // エラー時に適切なメッセージを表示する
} finally {
await db.close();
}
console.log("処理完了");
実行
node error-handling.js
結果
エラーが発生しました: SQLITE_ERROR: no such table: user
処理完了
メッセージが改善され、エラーが発生したということがわかりやすくなりました。また、catchによってエラーが適切に処理され、処理完了というメッセージが表示されるようになりました。
エラーハンドリングのベストプラクティス
- try-catch-finally文の使用 - catchで適切なエラー処理を実施する
- 具体的なエラーメッセージ - ユーザーにとって理解しやすいメッセージを提供
演習問題
以下の問題を解いて、データベース操作の理解を深めましょう。
演習1:エラーを発生させてみよう
先ほど書いたコードにエラーを発生させてみましょう。間違えたテーブル名を入力することでエラーを故意に発生させてみましょう。
insert.js
const result = await db.run(
"INSERT INTO user (name, email) VALUES (?, ?)", // users → userに変更
[name, email]
);
read.js
const users = await db.all("SELECT * FROM user"); // users → userに変更
update.js
const result = await db.run(
`UPDATE user SET name = ?, email = ? WHERE id = ?`, // users → userに変更
[newName, newEmail, userId]
);
delete.js
const result = await db.run(`DELETE FROM user`); // users → userに変更
それぞれのファイルを実行して、エラーが発生することを確認してください。
演習2:エラーハンドリングの追加
次のファイルに適切なエラーハンドリングを追加してください。
実装すべきファイル
- create.js
- read.js
- update.js
- delete.js
演習3:ユーザー管理システムの作成
ユーザー情報を管理するシステムを作成してください。以下の要件を満たす関数を実装しましょう。
要件
- user-manager.jsを作成して次の機能を実装してください。
- ユーザーの登録(名前、メールアドレス)
- ユーザー情報の取得(全ユーザー、特定のユーザー)
- ユーザー情報の更新
- ユーザー情報の削除
- 適切なエラーハンドリング
実装すべき関数
createUser(name, email)- ユーザー作成getAllUsers()- 全ユーザー取得getUserById(id)- ID指定でユーザー取得updateUser(id, name, email)- ユーザー更新deleteUser(id)- ユーザー削除
まとめ
この章では、Node.jsからデータベースに接続し、基本的なCRUD操作を行う方法を学習しました。
この章で学んだこと
- データベース接続: SQLiteを使用したNode.jsからのデータベース接続方法
- CRUD操作: データの作成(Create)、読み取り(Read)、更新(Update)、削除(Delete)
- エラーハンドリング: try-catch-finally文を使った適切なエラー処理