JDBCでデータベースを操作してみよう!

docs

今回は、そのJDBCを使って実際にJavaプログラムからデータベースを操作する方法を、具体的なコードを交えながら見ていこう!

JDBCと聞くと難しそうに感じるかもしれないけど、基本的な流れは決まっているから安心してね。今回はSQLiteというファイルベースの軽量なデータベースを使って説明するよ。これなら特別なサーバーを用意する必要がないから、すぐに試せるはずだ。

JDBC操作の基本的な流れ

JDBCでデータベースを操作する手順は、だいたい以下の4ステップに分けられるんだ。

  1. JDBCドライバーの読み込み
  2. データベースへの接続
  3. SQL文の実行
  4. データベースとの切断

この流れをしっかり頭に入れておくと、どんなデータベースを扱うときでも応用できるからね!

準備をしよう!

まずは、JDBCドライバーを準備しよう。今回はSQLiteを使うから、SQLite JDBCドライバーをプロジェクトに追加する必要があるよ。Mavenを使っているならpom.xmlに以下を追加すればOKだ。

XML

<dependency>
    <groupId>org.xerial</groupId>
    <artifactId>sqlite-jdbc</artifactId>
    <version>3.45.1.0</version>
</dependency>

Mavenを使っていない場合は、SQLite JDBCの公式ページからjarファイルをダウンロードして、プロジェクトのビルドパスに追加してね。

1. JDBCドライバーの読み込み

昔はClass.forName()を使ってドライバーを明示的に読み込む必要があったんだけど、最近のJDBCドライバーはService Provider Interface (SPI) を使っているので、ほとんどの場合この記述は不要なんだ。でも、もし古いバージョンのドライバーを使う場合や、何か問題が起きた場合は、覚えておくと良いかもしれないね。

Java

// 最近のJDBCドライバーではほとんどの場合不要
// Class.forName("org.sqlite.JDBC");

2. データベースへの接続

データベースに接続するには、DriverManager.getConnection()メソッドを使うよ。このメソッドには、接続するデータベースのURLと、必要であればユーザー名とパスワードを渡すんだ。SQLiteの場合はファイルパスを指定するだけだよ。

Java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DbConnectionExample {
    public static void main(String[] args) {
        String url = "jdbc:sqlite:test.db"; // test.dbというファイルが作成される

        try (Connection conn = DriverManager.getConnection(url)) {
            System.out.println("データベースに接続しました!");
            // ここでデータベース操作を行う
        } catch (SQLException e) {
            System.err.println("データベース接続エラー: " + e.getMessage());
        }
    }
}

ここで使っているtry-with-resources文は、Connectionのようなリソースを自動的にクローズしてくれる便利な構文だよ。これを使うと、finallyブロックでclose()を呼び出す手間が省けるし、クローズし忘れによるエラーも防げるから、積極的に使っていこう!

3. SQL文の実行

データベースに接続できたら、次はSQL文を実行してみよう。SQL文を実行するには、主に以下の2つのインターフェースを使うよ。

  • Statement: 静的なSQL文を実行する場合
  • PreparedStatement: パラメータを含むSQL文を実行する場合(SQLインジェクション対策にもなる!)

今回はPreparedStatementを中心に見ていこう。セキュリティ的にもこちらを使うのがおすすめだよ。

テーブルの作成

まずは、データを格納するテーブルを作ってみよう。Statementを使ってテーブルを作成する例だよ。

Java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class CreateTableExample {
    public static void main(String[] args) {
        String url = "jdbc:sqlite:test.db";

        try (Connection conn = DriverManager.getConnection(url);
             Statement stmt = conn.createStatement()) { // Statementを作成
            
            String sql = "CREATE TABLE IF NOT EXISTS users (" +
                         "id INTEGER PRIMARY KEY AUTOINCREMENT," +
                         "name TEXT NOT NULL," +
                         "age INTEGER)";
            
            stmt.execute(sql); // SQL文を実行
            System.out.println("usersテーブルが作成されたか、すでに存在します。");
            
        } catch (SQLException e) {
            System.err.println("テーブル作成エラー: " + e.getMessage());
        }
    }
}

IF NOT EXISTSとつけることで、もしテーブルがすでに存在していたとしてもエラーにならないようにしているんだ。便利だね!

データの挿入(INSERT)

次に、作ったテーブルにデータを挿入してみよう。ここではPreparedStatementの出番だよ!

Java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class InsertDataExample {
    public static void main(String[] args) {
        String url = "jdbc:sqlite:test.db";

        try (Connection conn = DriverManager.getConnection(url)) {
            String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
            try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                
                // 1人目のユーザー
                pstmt.setString(1, "田中 太郎"); // 1番目の?に値をセット
                pstmt.setInt(2, 30);      // 2番目の?に値をセット
                pstmt.executeUpdate();     // 実行
                System.out.println("田中 太郎のデータを挿入しました。");

                // 2人目のユーザー
                pstmt.setString(1, "佐藤 花子");
                pstmt.setInt(2, 25);
                pstmt.executeUpdate();
                System.out.println("佐藤 花子のデータを挿入しました。");
                
            }
        } catch (SQLException e) {
            System.err.println("データ挿入エラー: " + e.getMessage());
        }
    }
}

?を使うことで、SQL文に直接値を埋め込まずに済むのがPreparedStatementの大きな特徴だよ。これにより、悪意のあるSQLインジェクション攻撃からシステムを守ることができるんだ。それぞれのsetXXX()メソッドで、対応するデータ型の値をセットするよ。

データの取得(SELECT)

データベースにデータが入ったから、今度はそれをJavaプログラムから読み出してみよう!データの取得にはexecuteQuery()メソッドを使うよ。結果はResultSetというオブジェクトで返ってくるんだ。

Java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class SelectDataExample {
    public static void main(String[] args) {
        String url = "jdbc:sqlite:test.db";

        try (Connection conn = DriverManager.getConnection(url)) {
            String sql = "SELECT id, name, age FROM users WHERE age >= ?";
            try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                pstmt.setInt(1, 28); // 28歳以上のユーザーを検索

                try (ResultSet rs = pstmt.executeQuery()) { // データを取得
                    while (rs.next()) { // 次の行がある限りループ
                        int id = rs.getInt("id");       // "id"列のint値を取得
                        String name = rs.getString("name"); // "name"列のString値を取得
                        int age = rs.getInt("age");     // "age"列のint値を取得
                        System.out.println("ID: " + id + ", 名前: " + name + ", 年齢: " + age);
                    }
                }
            }
        } catch (SQLException e) {
            System.err.println("データ取得エラー: " + e.getMessage());
        }
    }
}

ResultSetは、取得したデータを行ごとに処理するためのカーソルみたいなものだとイメージしてね。rs.next()で次の行に移動して、データがある場合はtrueを返すから、whileループで全ての行を処理できるんだ。各列の値は、getInt(), getString()などのメソッドを使って取得するよ。列名か列のインデックス(1から始まる)で指定できるけど、列名で指定する方が可読性が高いからおすすめだ。

データの更新(UPDATE)

既存のデータを更新してみよう。これもPreparedStatementを使ってexecuteUpdate()メソッドで実行するよ。

Java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class UpdateDataExample {
    public static void main(String[] args) {
        String url = "jdbc:sqlite:test.db";

        try (Connection conn = DriverManager.getConnection(url)) {
            String sql = "UPDATE users SET age = ? WHERE name = ?";
            try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                pstmt.setInt(1, 31);       // 新しい年齢
                pstmt.setString(2, "田中 太郎"); // 更新対象の名前
                
                int rowsAffected = pstmt.executeUpdate(); // 更新された行数を取得
                if (rowsAffected > 0) {
                    System.out.println("田中 太郎の年齢を更新しました。");
                } else {
                    System.out.println("田中 太郎は見つかりませんでした。");
                }
            }
        } catch (SQLException e) {
            System.err.println("データ更新エラー: " + e.getMessage());
        }
    }
}

executeUpdate()は、INSERTUPDATEDELETE文の実行に使われるよ。実行された行数を返すから、更新が成功したかどうかの確認にも使えるんだ。

データの削除(DELETE)

最後に、いらないデータを削除してみよう。これもexecuteUpdate()を使うよ。

Java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class DeleteDataExample {
    public static void main(String[] args) {
        String url = "jdbc:sqlite:test.db";

        try (Connection conn = DriverManager.getConnection(url)) {
            String sql = "DELETE FROM users WHERE name = ?";
            try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                pstmt.setString(1, "佐藤 花子"); // 削除対象の名前
                
                int rowsAffected = pstmt.executeUpdate();
                if (rowsAffected > 0) {
                    System.out.println("佐藤 花子のデータを削除しました。");
                } else {
                    System.out.println("佐藤 花子は見つかりませんでした。");
                }
            }
        } catch (SQLException e) {
            System.err.println("データ削除エラー: " + e.getMessage());
        }
    }
}

これで、データベースの基本的な操作であるCRUD(Create, Read, Update, Delete)を一通りJavaから実行する方法が分かったね!

4. データベースとの切断

これは超重要なステップだよ!データベースとの接続は、使い終わったら必ず切断する必要があるんだ。もし切断し忘れると、データベースのリソースを圧迫したり、予期せぬエラーの原因になったりするから注意してね。

上で説明したtry-with-resources文を使えば、ConnectionStatementResultSetなどのリソースが自動的にクローズされるから、この心配はほとんどなくなるよ。だから、積極的にtry-with-resourcesを使っていこう!

Java

// try-with-resourcesを使えば自動的にクローズされる
try (Connection conn = DriverManager.getConnection(url);
     PreparedStatement pstmt = conn.prepareStatement(sql);
     ResultSet rs = pstmt.executeQuery()) {
    // ... 処理 ...
} catch (SQLException e) {
    // ... エラーハンドリング ...
}

まとめ

今回は、JDBCを使ってJavaからデータベースを操作する基本的な方法を、具体的なコードをたくさん使いながら解説したよ。

  • JDBC操作は「ドライバー読み込み」「接続」「SQL実行」「切断」の4ステップ!
  • try-with-resources文でリソースのクローズ忘れを防ごう!
  • SQLインジェクション対策としてPreparedStatementを使おう!

これで、君もJavaでデータベースと会話できるようになったはずだ!最初は少し戸惑うかもしれないけど、何度も手を動かしてコードを書いてみることが上達の近道だよ。

もっと詳しく知りたいことや、こんなこともできるの?といった疑問があったら、ぜひコメントで教えてね。


これまでの記事もチェック!

コメント

タイトルとURLをコピーしました