
JDBCとは?基本概念と仕組み
JDBC(Java Database Connectivity)を使えば、Javaアプリとデータベースを直接連携できます。本記事では、JDBCの基本から実装方法までを詳しく解説し、Todoアプリとデータベースを連携させる方法を紹介します。
JDBCを使用することで、SQLを自由に記述でき、より細かい制御が可能になるため、軽量なアプリケーションにおいてもオーバーヘッドを抑えた効率的なデータベース処理が実現できます。
なお、本記事ではJDBCを使用した基本的なデータ操作(追加・削除)を中心に解説します。
データの更新処理や、より効率的なデータベース接続を実現する「コネクションプール」の導入については、別記事にて詳しく解説しますので、必要に応じてそちらもご参照ください。
JDBCの概要
JDBC(Java Database Connectivity)は、Javaアプリケーションとリレーショナルデータベースを接続するためのAPIです。JDBCを利用することで、SQLクエリを発行し、データの取得や更新を行うことができます。
JDBCを使用する主な手順は以下の通りです。
- JDBCドライバをロードする
- データベースに接続する
- SQLクエリを実行する
- 結果を取得・処理する
- 接続を閉じる
JDBCの主要コンポーネント
JDBCを構成する主なコンポーネントを理解しておくことで、効率的なデータベース操作が可能になります。
JDBCの主要コンポーネント
- Connection: データベースとの接続を管理する
- Statement: SQLクエリを実行する
- PreparedStatement: 事前にコンパイルされたSQLを実行する(セキュリティとパフォーマンス向上のため推奨)
- ResultSet: SQLクエリの結果を取得・処理する
JavaアプリからMySQLに接続する
JavaアプリケーションがMySQLに接続するためには、JDBCドライバ(MySQL Connector/J)を経由する必要があります。 今回は、Databaseへの接続には、前回の「【Javaの基礎知識】DockerでMySQL環境を構築!」記事内で作成済みのDocker環境を再利用します。 以下の図は、その接続の流れを示したものです。

- ローカルPC: Eclipseを使用してJavaアプリを開発・実行する環境
- Eclipse: Javaアプリケーションの開発環境(IDE)
- Javaアプリ(JDBC API): JDBCを利用してデータベースにアクセスするJavaプログラム
- JDBCドライバ(MySQL Connector/J): JavaアプリとMySQLの間で通信を仲介する
- MySQLコンテナ(Docker): Dockerで動作するMySQL環境
- ポート3306: JavaアプリがMySQLに接続するための通信ポート
この構成を利用することで、ローカルPCにMySQLを直接インストールせずに、Dockerを使って簡単に開発環境を構築できます。
Todoアプリの概要と設計
本記事では、JDBCを使用してデータベースとTodoアプリを連携する方法を解説します。作成時点では、以下の基本機能を実装しています。
✅ 実装済みの機能
- 一覧表示:データベースから取得したTodoリストを画面に表示
- 新規追加:フォームから入力したタスクをデータベースへ登録
- 削除:登録済みのタスクを削除
🔧 仕様
今回は「【Javaの基礎知識】Servlet/JSPでTodoアプリを作ろう」記事で作成したTodoアプリへ、新たにデータベース接続機能を追加し、JDBCを活用してデータを永続化できるようにします。
機能 | 仕様概要 |
---|---|
一覧表示 | データベースの todo_items テーブルから全件取得し表示 |
新規追加 | ユーザー入力を受け付け、新しいTodoをデータベースに保存 |
削除 | 指定されたTodoをデータベースから削除 |
- JDBCを使用してMySQLと接続
- Servlet/JSPで実装し、Webアプリとして動作
- データベース連携の基本機能(追加・削除・一覧表示)の実装
Todoアプリの完成イメージ
本記事では、JDBCを用いてデータベースと連携したTodoアプリを作成します。ここでは、完成後のアプリの動作イメージを紹介し、一覧表示・追加・削除の基本機能がどのように動作するかを確認します。
Todoアプリ初期表示
ブラウザから http://localhost:8080/todo にアクセスすると、以下のようにTodoリストが表示されます。

Todoアプリの追加画面
「タイトル」を入力して「追加」ボタンをクリックすると、新しいTodoがリストに追加されます。


Todoアプリの削除画面
登録されたTodoの「削除」ボタンをクリックすると、対象のTodoがリストから削除されます。


データベースを作成する
JDBCを使ってデータベースと接続する前に、まずはMySQLにデータベースを作成する必要があります。本記事では、`todo_db` という名前のデータベースを作成し、タスク管理用のテーブル `todo_items` を用意します。
MySQLにデータベースを作成
MySQLにログインし、以下のSQLコマンドを実行して `todo_db` を作成します。
CREATE DATABASE todo_db;
正しく作成されたか確認するため、以下のコマンドを実行します。
SHOW DATABASES;
データベース一覧に `todo_db` が表示されていれば成功です。
データベースを選択する
作成したデータベースを使用するために、次のコマンドを実行します。
USE todo_db;
このコマンドを実行すると、以降のSQL操作は `todo_db` に対して行われます。
タスク管理用のテーブルを作成
データを保存するために、`todo_items` テーブルを作成します。
CREATE TABLE todo_items (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
completed BOOLEAN DEFAULT FALSE
);
この todo_items テーブルには、以下のカラムが含まれています。
カラム名 | データ型 | 説明 |
---|---|---|
id | INT AUTO_INCREMENT PRIMARY KEY | 各タスクに割り当てられる一意のID |
title | VARCHAR(255) NOT NULL | タスクのタイトル |
completed | BOOLEAN DEFAULT FALSE | タスクの完了状態(初期値は未完了) |
テーブルが作成されたか確認
以下のコマンドを実行して、todo_items テーブルが作成されているか確認します。
SHOW TABLES;
出力結果に todo_items が含まれていれば、テーブル作成は成功です。
サンプルデータを挿入
動作確認のため、サンプルデータを挿入します。
INSERT INTO todo_items (title, completed) VALUES ('タスク1', false);
INSERT INTO todo_items (title, completed) VALUES ('タスク2', true);
挿入されたデータを確認するには、次のコマンドを実行します。
SELECT * FROM todo_items;
これで、データベースの準備が完了しました。次に、JDBCを使用してこのデータベースと接続し、データの取得・追加・更新・削除を行います。
JDBC接続専用クラスを作成する
本記事では、前回作成したTodoアプリを JDBC を使ってデータベースと接続し、タスクを管理できるようにする方法を解説します。
JDBCを使うことで、以下のようなデータ操作が可能になります。
- Todoアイテムの一覧を取得する
- 新しいTodoアイテムを追加する
- Todoアイテムの完了状態を更新する
- Todoアイテムを削除する
本記事では、初心者でも理解できるように、「なぜこの作業が必要なのか」を丁寧に説明しながら進めます。
JDBCを使うための準備
JDBCを利用するには、いくつかの準備が必要です。まずは、データを保存するためのデータベースを作成し、Javaアプリケーションから接続できる環境を整えます。次に、JDBCを使用するためのドライバをプロジェクトに追加し、データベースとやり取りする準備を行います。これらの手順を一つずつ丁寧に解説していくので、順番に進めていきましょう。
① MySQLのデータベースを作成する
まず、MySQLに Todoアプリのデータを保存するデータベース を作成します。
CREATE DATABASE todo_db;
USE todo_db;
CREATE TABLE todo_items (
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
completed TINYINT(1) DEFAULT 0
);
② JDBCドライバをプロジェクトに追加する
JDBCを使うために、MySQLのJDBCドライバ(mysql-connector-java.jar)をプロジェクトに追加します。
- Eclipseの場合:「プロジェクトのビルドパス」にJARファイルを追加
- 手動で lib フォルダを作成し、その中にJARを配置
データベースと接続するクラスを作成
JDBCを使うためには、データベースに接続するクラスを作成する必要があります。
今回は、DatabaseへのConnectionクラスとして、前回の「【Javaの基礎知識】DockerでMySQL環境を構築!」記事内で作成済みの「MySQLConnection」クラスを再利用します。外部クラスから接続を取得できるようにするためのgetterメソッドを作成し、各DAOクラスで利用できるようにします。
現在のプロジェクト構成は以下のようになっています。
【対象ファイル】
1 2 3 | com.example.todo/ └── MySQLConnection.java └── getConnection() ⇨ getterメソッドを追加 |
この状態から、MySQLConnection.java に getConnection() メソッドを追加 し、JDBCを利用する各DAOクラスで接続を取得できるようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | package com.example.todo; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class MySQLConnection { // データベース接続情報 private static final String URL = "jdbc:mysql://localhost:3306/todo_db"; private static final String USER = "root"; private static final String PASSWORD = "password"; // データベース接続を管理する変数 private static Connection connection = null; // データベース接続を取得するメソッド(Getter) public static Connection getConnection() throws SQLException { if (connection == null || connection.isClosed()) { connection = DriverManager.getConnection(URL, USER, PASSWORD); } return connection; } // データベース接続を閉じるメソッド public static void closeConnection() { try { if (connection != null && !connection.isClosed()) { connection.close(); } } catch (SQLException e) { e.printStackTrace(); } } } |
- データベース接続情報の管理
- データベースのURL、ユーザー名、パスワードを定数として定義
- 接続先のデータベース情報を一元管理することで、変更時の影響を最小限に抑える
- データベース接続の確立
- JDBCの DriverManager.getConnection() を使用して、データベースとの接続を確立
- このメソッドをDAOクラスで呼び出すことで、各処理で個別に接続を作成する手間を省く
- 接続の管理
- 各DAOでデータベース操作が終わった後は、接続を適切に閉じる必要がある
- このクラスを使用することで、接続の確立が統一され、誤った接続管理のリスクを減らせる
DatabaseConnection クラスのポイント
データベース接続情報を定数として管理し、一元化する
メソッド getConnection() で接続を取得できるようにする
エラーハンドリングは、DAOクラス側で SQLException を適切に処理する
DAO(Data Access Object)クラスを作成する
ここでは、JDBCを使ってデータベースを操作する DAO(Data Access Object)クラス を作成します。
DAOクラスは、データベースの処理(データの取得・追加・更新・削除)を 一元管理するための専用クラス です。
DAOクラスとは?
DAOとは、データベースとやり取りする処理を1つのクラスにまとめ、アプリケーションの可読性や保守性を向上させる設計パターンです。
Servletや他のクラスが直接データベースにアクセスせず、DAOを通じて操作を行うことで、コードの分離が可能になります。
DAOクラスとMVCの関係
アプリケーション開発では、MVC(Model-View-Controller)アーキテクチャ に基づいてコードを分割することで、管理しやすい設計にします。
- Model(モデル) - データの管理を担当(DAOクラスはここに該当)
- View(ビュー) - ユーザーに表示する画面(JSPなど)
- Controller(コントローラー) - リクエストを受け取り、ModelとViewをつなぐ(Servletが担当)
今回作成する TodoDAOクラス は、MVCの「Model(モデル)」に該当 し、データベースとのやり取りを一括して管理します。
この設計を採用することで、**Servlet(Controller)がデータベースの処理を直接記述せず、ロジックをDAOに集約する** ことができます。
DAOクラスの役割
DAOクラスでは、以下の4つのデータベース操作を行います。
- Todoアイテムの一覧を取得( getAllTodos())
- 新しいTodoアイテムを追加( addTodo())
- Todoアイテムの状態を更新( updateTodo())
- Todoアイテムを削除( deleteTodo())
DAOを導入することで、以下のようなメリットがあります。
- コードの分離: Servletがデータ処理の責務を持たず、ビジネスロジックとデータアクセスを分離できる
- 再利用性の向上: 複数のServletやクラスでデータアクセスロジックを統一的に利用可能
- 可読性の向上: SQLの記述をDAO内にまとめることで、コードが見やすくなる
現在のプロジェクト構成は以下のようになっています。
【対象ファイル】
1 2 3 4 5 6 7 8 | com.example.todo/ ├── MySQLConnection.java ├── Todo.java └── TodoDAO.java ⇨ 新規作成 ├── getAllTodos() ⇨ 追加 ├── addTodo() ⇨ 追加 ├── updateTodo() ⇨ 今回は作成しません └── deleteTodo() ⇨ 追加 |
この状態から、新しく TodoDAO.java を作成し、データベースとのやり取りをDAOクラスに統一します。各メソッドで データの取得・追加・更新・削除(CRUD) を実装し、Servlet側ではDAOを呼び出すだけでデータ操作が行えるようにします。
DAOクラスの作成
まず、DAOクラス全体の構造を確認します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | package com.example.todo; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class TodoDAO { public List<Todo> getAllTodos() { List<Todo> todos = new ArrayList<>(); String sql = "SELECT id, title FROM todo_items"; try (Connection conn = MySQLConnection.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql); ResultSet rs = pstmt.executeQuery()) { while (rs.next()) { todos.add(new Todo(rs.getInt("id"), rs.getString("title"))); } } catch (SQLException e) { e.printStackTrace(); } return todos; } public void addTodo(String title) { String sql = "INSERT INTO todo_items (title) VALUES (?)"; try (Connection conn = MySQLConnection.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, title); pstmt.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } } public void deleteTodo(int id) { String sql = "DELETE FROM todo_items WHERE id = ?"; try (Connection conn = MySQLConnection.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setInt(1, id); pstmt.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } } } |
このクラスを作成することで、アプリケーションの中でデータベース操作を DAOクラスに統一 することができます。
Todoアイテム一覧を取得する
public List<String> getAllTodos() {
List<String> todos = new ArrayList<>();
String sql = "SELECT title FROM todo_items";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
todos.add(new Todo(rs.getInt("id"), rs.getString("title")));
}
} catch (SQLException e) {
e.printStackTrace();
}
return todos;
}
このメソッドは、データベースからTodoアイテムの一覧を取得するための処理を行います。
- SQLクエリの作成
- データベースから全てのTodoアイテムのタイトルを取得するためのSQLを作成
- 使用するSQL:
SELECT title FROM todo_items;
- データベース接続の確立
- `DatabaseConnection.getConnection()` を使用してデータベースに接続
- 使用するコード:
Connection conn = DatabaseConnection.getConnection();
- SQLの実行準備
- `PreparedStatement` を使用してSQLを実行する準備
- 使用するコード:
PreparedStatement pstmt = conn.prepareStatement(sql);
- クエリの実行と結果の取得
- `executeQuery()` を使用してクエリを実行し、結果を `ResultSet` に格納
- 使用するコード:
ResultSet rs = pstmt.executeQuery();
- データのリストへの格納
- `while` ループを使用して `ResultSet` からデータを取得し、リストに追加
- 使用するコード:
while (rs.next()) {
todos.add(new Todo(rs.getInt("id"), rs.getString("title")));
}
- 例外処理とエラーハンドリング
- データベース接続やクエリ実行中にエラーが発生した場合、`SQLException` をキャッチし、エラーメッセージを出力
- 使用するコード:
} catch (SQLException e) {
e.printStackTrace();
}
- 取得したデータの返却
- リスト `todos` をメソッドの呼び出し元に返す
- 使用するコード:
return todos;
新しいTodoアイテムを追加する
public void addTodo(String title) {
String sql = "INSERT INTO todo_items (title) VALUES (?)";
try (Connection conn = DatabaseConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, title);
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
このメソッドは、データベースに新しいTodoアイテムを追加するための処理を行います。
- SQLクエリの作成
- データベースに新しいTodoアイテムを挿入するためのSQLを作成
- 使用するSQL:
INSERT INTO todo_items (title) VALUES (?)
- データベース接続の確立
- `DatabaseConnection.getConnection()` を使用してデータベースに接続
- 使用するコード:
Connection conn = DatabaseConnection.getConnection();
- SQLの実行準備
- `PreparedStatement` を使用してSQLを実行する準備
- 使用するコード:
PreparedStatement pstmt = conn.prepareStatement(sql);
- データのセット
- プレースホルダ `?` に挿入する値を設定
- 使用するコード:
pstmt.setString(1, title);
- クエリの実行
- `executeUpdate()` を使用してSQLを実行し、新しいデータをデータベースに追加
- 使用するコード:
pstmt.executeUpdate();
- 例外処理とエラーハンドリング
- データベース接続やクエリ実行中にエラーが発生した場合、`SQLException` をキャッチし、エラーメッセージを出力
- 使用するコード:
} catch (SQLException e) {
e.printStackTrace();
}
Todoアイテムを削除する
public void deleteTodo(String title) {
String sql = "DELETE FROM todo_items WHERE id = ?";
try (Connection conn = MySQLConnection.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, id);
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
このメソッドは、指定したTodoアイテムを削除する処理を行います。
- 削除対象の指定
- 削除するアイテムを特定するために title を指定
- SQLクエリの作成
- 指定した id のTodoアイテムを削除するSQLを作成
- 使用するSQL:
DELETE FROM todo_items WHERE id =
- データベース接続の確立
- データベースと接続し、SQLを実行できる状態にする
- 使用するコード:
Connection conn = DatabaseConnection.getConnection();
- SQLの実行準備
- PreparedStatement を使用してSQLを実行する準備
- 使用するコード:
PreparedStatement pstmt = conn.prepareStatement(sql);
- 削除するデータのセット
- ? に id の値を設定
- 使用するコード:
stmt.setString(1, id);
- クエリの実行
- executeUpdate() を使用して指定したIDのデータを削除
- 使用するコード:
pstmt.executeUpdate();
- 例外処理とエラーハンドリング
- SQLの実行時に発生する可能性のあるエラーを SQLException でキャッチ
- エラー発生時にスタックトレースを出力
- 使用するコード:
} catch (SQLException e){
e.printStackTrace();
}
以下のメソッドを実装することで、Todoアプリのデータを柔軟に操作できます。
処理 | SQL | 対応メソッド |
---|---|---|
データ取得 | SELECT title FROM todo_items | getAllTodos() |
データ追加 | INSERT INTO todo_items (title) VALUES (?) | addTodo(String title) |
データ更新 | UPDATE todo_items SET completed = ? WHERE id = ? | updateTodo(int id, boolean completed) |
データ削除 | DELETE FROM todo_items WHERE id = ? | deleteTodo(int id) |
この実装を行うことで、Todoアプリのデータを取得・追加・更新・削除できるようになります。
JavaBeans(Java特有の構造体)を作成する
JavaBeans(ジャバビーンズ)は、Java特有のデータ構造であり、他のプログラミング言語にはない独自の設計ルールを持つクラスです。
Javaにおける「構造体(struct)」のような役割を果たしつつ、オブジェクト指向設計を前提とした規約に基づいています。
JavaBeansとは?
JavaBeansは、Javaにおけるデータ管理の標準的な方法であり、以下のルールに従います。
- プライベートなフィールドを持ち、ゲッター・セッターを通じてアクセスする(カプセル化の徹底)
- 引数なしのデフォルトコンストラクタを持つ(フレームワークでの利用を考慮)
- シリアライズ可能( Serializable を実装することが推奨)
- 他の言語の「構造体(struct)」とは異なり、オブジェクト指向の原則に従う
JavaBeansは、「単なるデータの塊」ではなく、「データを適切に管理するためのクラス」です。
そのため、外部から直接データを変更できないようにし、必ずゲッター・セッターを経由してデータの取得・変更を行います。
ゲッター(Getter)とセッター(Setter)とは?
JavaBeansでは、データ(フィールド)を直接変更できません。
そのため、データを取得・変更するために「ゲッター(getter)」と「セッター(setter)」を使用します。
メソッドの種類 | 役割 |
---|---|
ゲッター(Getter) | オブジェクトのデータを取得する( getXxx() 形式) |
セッター(Setter) | オブジェクトのデータを更新する( setXxx() 形式) |
ゲッター・セッターのルール
- ゲッター → フィールド名の先頭を大文字にし、 get をつける(例: getTitle())
- セッター → フィールド名の先頭を大文字にし、 set をつける(例: setTitle(String title))
Todoクラスの実装
新規作成: Todo.java は、タスク情報(IDとタイトル)を管理する JavaBeans です。
【対象ファイル】
1 2 3 | com.example.todo ├── MySQLConnection.java └── Todo.java ⇨ 新規作成 |
以下の Todo クラスは、JavaBeansの規約に基づき、ID( id)とタイトル( title)を管理します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | package com.example.todo; public class Todo { private int id; private String title; // デフォルトコンストラクタ public Todo() {} // ID付きのコンストラクタ public Todo(int id, String title) { this.id = id; this.title = title; } // ゲッター(データの取得用) public int getId() { return id; } // セッター(データの更新用) public String getTitle() { return title; } } |
JavaBeansは、Java特有のデータ管理クラスであり、オブジェクト指向設計に基づく構造体です。
- データのカプセル化を徹底し、ゲッター・セッターで安全にアクセス
- デフォルトコンストラクタを持ち、柔軟なオブジェクト生成が可能
- シリアライズ対応し、永続化にも適した設計
TodoServletクラスを作成する
これまでに、データベース接続専用の MySQLConnection クラスと、データ操作を担当する DAO(Data Access Object) を作成しました。
次のステップとして、Servletクラスである TodoServlet を作成し、DAOを経由してデータベースと連携する仕組みを構築します。
- DAOを使用するため、new TodoDAO() を追加
- データベース操作をDAO経由に変更し、Servlet内でSQLを直接記述しないようにする
現在のプロジェクト構成は以下のようになっています。
【編集予定のファイル】
1 2 3 4 5 6 7 | com.example.todo/ ├── MySQLConnection.java ├── Todo.java ├── TodoDAO.java └── TodoServlet.java ⇨ 新規作成 ├── new doGet() ⇨ 追加 └── new doPost() ⇨ 追加 |
既存の「com.example.todo」パッケージへTodoServlet.java を新規に作成し、DAOを使ったデータ操作ができるようにします。これにより、Servletがデータ処理を直接担うのではなく、DAOに処理を委譲する形になります。
これでデータベース操作を専用のDAOクラスに集約し、Servletの役割をリクエストの制御に特化 させることで、コードの分離と保守性の向上を図ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | package com.example.todo; import java.io.IOException; import java.util.List; import jakarta.servlet.RequestDispatcher; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @WebServlet("/todo") public class TodoServlet extends HttpServlet { private TodoDAO todoDAO = new TodoDAO(); protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("TodoServlet: doGet() が呼ばれました"); List<Todo> todos = todoDAO.getAllTodos(); request.setAttribute("todos", todos); RequestDispatcher dispatcher = request.getRequestDispatcher("/index.jsp"); dispatcher.forward(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String title = request.getParameter("title"); String deleteId = request.getParameter("delete"); if (deleteId != null && !deleteId.trim().isEmpty()) { try { int id = Integer.parseInt(deleteId); todoDAO.deleteTodo(id); } catch (NumberFormatException e) { e.printStackTrace(); } } else if (title != null && !title.trim().isEmpty()) { todoDAO.addTodo(title); } response.sendRedirect(request.getContextPath() + "/todo"); } } |
ServletのURLマッピングについて
ServletをWebアプリケーションで動作させるには、URLとの関連付け(マッピング)が必要です。
ServletのURLマッピングには、以下の2つの方法があります。
- ① @WebServlet アノテーションを使用する(推奨)
- ② web.xml にURLマッピングを記述する
本記事では、よりシンプルに管理できる @WebServlet` を採用します。
@WebServlet アノテーションを使用する方法
Servletのクラスに @WebServlet を記述するだけで、web.xml なしでURLマッピングが可能 です。
この方法を使うと、ServletとURLの関係がコード内に明示され、管理が容易になります。
@WebServlet("/todo")
public class TodoAServlet extends HttpServlet {
private TodoDAO todoDAO = new TodoDAO();
}
この設定により、 http://localhost:8080/TodoApp/todo にアクセスすると TodoServlet が実行されます。
web.xml にURLマッピングを記述する方法
古いプロジェクトや特定の環境では、web.xml を使ってServletのURLマッピングを行うことがあります。
<servlet>
<servlet-name>TodoServlet</servlet-name>
<servlet-class>com.example.todo.TodoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TodoServlet</servlet-name>
<url-pattern>/todo</url-pattern>
</servlet-mapping>
この設定により、 http://localhost:8080/TodoApp/todo にアクセスすると TodoServlet が実行されます。
どちらを使うべきか?
一般的には、以下の基準で選択します。
方法 | メリット | デメリット |
---|---|---|
① @WebServlet(推奨) | コード内でURLを管理でき、設定がシンプル | レガシーな環境では使用できない場合がある |
② web.xml | 複数のServletを一元管理できる | 設定が冗長になり、修正時にミスが発生しやすい |
本記事では、最新の開発環境に適した @WebServlet を採用 し、ServletのURLマッピングを設定します。
JDBCのトラブルシューティングと注意点
JDBCを扱う際に起こりがちなエラーとその解決策を紹介します。
よくあるエラーと対処法
JDBCを使用する際、環境設定やコードのミスにより発生しやすいエラーと、その対処方法について説明します。
エラー | 原因 | 対処法 |
---|---|---|
java.sql.SQLException: No suitable driver found | JDBCドライバーが正しくロードされていない |
|
java.sql.SQLSyntaxErrorException | SQL文に誤りがある |
|
java.sql.SQLTimeoutException | データベース接続がタイムアウトしている |
|
セキュリティ対策とベストプラクティス
JDBCを使用する際は、SQLインジェクションなどのセキュリティリスクに注意が必要です。以下の対策を実施することで、安全なアプリケーションを構築できます。
SQLインジェクション対策
SQLインジェクション攻撃を防ぐために、 PreparedStatement を使用しましょう。
String sql = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, inputUsername); // ユーザー入力をバインド
ResultSet rs = pstmt.executeQuery();
- ユーザー入力を直接SQLに埋め込まず、 PreparedStatement でバインドする
- データベース接続ユーザーには最低限の権限を付与する(書き込み不要なら SELECT のみ)
エラーハンドリングとログ管理
エラーが発生した際に、適切な対応を行うためのハンドリングとログ管理が重要です。
- エラーメッセージをユーザーに直接表示せず、適切なメッセージを返す
- 例外発生時に SQLException をキャッチし、適切なログ出力を行う
try (Connection conn = MySQLConnection.getConnection()) {
// DB操作
} catch (SQLException e) {
logger.error("Database error: " + e.getMessage()); // エラーログを記録
}
(発展編)ORMとは?データベース操作を簡単にする技術
データベースを扱うアプリケーションでは、データの取得・追加・更新・削除(CRUD操作)が欠かせません。しかし、通常のSQLを直接記述する方法では、コードが複雑になり、保守性が低下してしまいます。
この問題を解決するために登場したのが ORM(Object-Relational Mapping) です。ここでは、ORMの基本概念やメリット、具体的な実装方法について軽く解説します。
ORMとは?
ORM(Object-Relational Mapping)は、オブジェクト指向言語(Java、Python など)とリレーショナルデータベース(MySQL、PostgreSQL など)をスムーズに連携させるための技術です。簡単に言うと、「SQLを直接書かずに、データベース操作をオブジェクト指向のコードで実装できる仕組み」 です。
従来のSQLベースのデータ操作
通常、データベース操作は SQL を使用して行います。例えば、Java の JDBC を使ってデータを取得する場合、次のようなコードになります。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TodoDAO {
public List<String> getAllTodos() {
List<String> todos = new ArrayList<>();
String sql = "SELECT title FROM todo_items";
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/todo_db", "root", "root");
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
todos.add(rs.getString("title"));
}
} catch (SQLException e) {
e.printStackTrace();
}
return todos;
}
}
このコードでは、データベースとの接続、SQLの準備、データ取得処理をすべて手動で行う必要があります。
ORMを使ったデータ操作
ORM を導入すると、データベース操作をオブジェクトとして扱えるようになり、SQLを直接書かずにデータ操作が可能になります。
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "todo_items")
public class Todo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private boolean completed;
// ゲッター・セッター省略
}
このように、データベースの todo_items テーブルに対応する Todoクラスを作成し、データ操作をオブジェクト指向で扱うことができます。
ORMを使うメリット
ORMを使うことで、以下のようなメリットがあります。
メリット | 説明 |
---|---|
SQLを直接書かなくて済む | プログラム内でデータ操作をオブジェクトのメソッドで記述できる |
コードの可読性が向上 | SQLの記述を減らし、コードがシンプルになる |
データベースの種類に依存しにくい | MySQLからPostgreSQLなどへ移行する際の変更が少なくて済む |
ORMを使うデメリット
ORMにはメリットだけでなく、いくつかのデメリットもあります。
- SQLの最適化がしづらい - ORMが生成するSQLは、手書きのSQLと比べて効率が悪くなることがある。
- 学習コストがある - JPA/Hibernate などのORMフレームワークを使うには、新しい知識が必要。
- 軽量なアプリにはオーバーヘッドが大きい - 小規模なプロジェクトでは、JDBCを直接使う方がシンプルで高速。
ORM(Object-Relational Mapping)は、データベース操作を簡単にし、コードの可読性を向上させる技術です。JDBCを使った直接的なデータ操作と比べ、オブジェクト指向のアプローチでデータベースを扱えるため、開発の効率が向上します。
しかし、SQLの最適化が難しい点や学習コストがあるため、プロジェクトの規模や要件に応じて、JDBCとORMを使い分けることが重要です。
JDBCとORMの違い
JDBCはデータベースと直接やり取りする一方で、ORM(Object-Relational Mapping)を使用すると、Javaのオブジェクト指向の考え方でデータを管理できます。以下の表で比較してみましょう。
項目 | JDBC | ORM(例: Hibernate) |
---|---|---|
開発の手間 | SQLを直接記述する必要がある | オブジェクト指向の操作でDBを管理 |
パフォーマンス | SQLを直接実行するため高速 | 抽象化レイヤーがあるためやや低速 |
保守性 | SQLの修正が必要 | コードの変更で柔軟に対応可能 |