[Java] JDBCのAPIでデータ検索・更新

JDBCのAPIを使用してDB操作をする方法について、いくつかまとめていきます。

JDBCを介してSQLを発行する場合、Statementインターフェースを使用します。Statementインターフェースには以下の種類があります。

1. Statementの種類
Statement パラメータなしのSQL文を実行する。コンパイルせずに文字列のままSQL文を発行するので、DBMSがSQL文を解析する。
PreparedStatement Statementインターフェースのサブインターフェースで、パラメータ付きのSQL文を実行することが出来る。SQL文はDBMSが理解できるようにあらかじめコンパイルして発行する。
CallableStatement Statementインターフェースのサブインターフェースで、ストアドプロシージャを実行することが出来る。

なお、この記事で使用するテーブルとして、以下のようなデータを用意しています。

テーブル名はarticles、idを主キーにtitle、bodyといったフィールドを保持したテーブルです。

Statementを利用してSQLを実行

Statementインスタンスを取得

Connectionオブジェクトから生成

Statementインターフェースのインスタンスは、ConnectionクラスのcreateStatementメソッドで生成します。

Connection conn = DriverManager.getConnection(url, user, password);
Statement statement = conn.createStatement();

Statementインスタンスの主なメソッド

Statementインターフェースの主なメソッドは以下の通りです。なお、これらのメソッドはサブインターフェースである、PreparedStatement、CallableStatementにもそれぞれ引き継がれます。

2. Statementインスタンスの主なメソッド
ResultSet executeQuery(String) 引数で指定されたデータ検索クエリ(SELECT)を実行する。戻り値は抽出結果をResultSet型で返す。
int executeUpdate(String) 引数で指定されたデータ更新クエリ(UPDATE/INSERT/DELETE)を実行する。戻り値は更新件数を返す。
boolean execute(String) 引数で指定されたクエリを実行する。戻り値は実行結果の成否を返す。

データ検索

コード例

このコードではid列とtitle列を抽出してコンソールへ出力しています。

Statement statement = conn.createStatement();
ResultSet results = statement.executeQuery("select id, title from articles");
while (results.next()) {
    System.out.println(
            "id:" + results.getInt("id") +
            ", title:" + results.getString("title"));
}

ResultSetオブジェクトのgetXXXメソッドで抽出したフィールド情報を取得します。これはフィールド名をStringで指定する方法と、カラムインデックス(int)で指定する方法があり、以下のように置き換えることが出来ます。

Statement statement = conn.createStatement();
ResultSet results = statement.executeQuery("select id, title from articles");
while (results.next()) {
    System.out.println(
            "id:" + results.getInt(1) +
            ", title:" + results.getString(2));
}
  • ResultSet.nextメソッドは抽出結果行のカーソルを1行進める。最終行に達したらfalseを返す。
  • ResultSet.getXXXメソッドでカラムインデックスを指定するときインデックスは、1から開始される。

[ソースコード全体はコチラ]

import java.sql.*;

public class JdbcTest {
    public static void main(String[] args) throws SQLException {
        String url = "jdbc:mysql://localhost/test";
        String user = "user";
        String password = "password";

        try (Connection conn = DriverManager.getConnection(url, user, password);) {
            Statement statement = conn.createStatement();
            ResultSet results = statement.executeQuery("select id, title from articles");
            while (results.next()) {
                System.out.println(
                        "id:" + results.getInt("title") +
                        ", title:" + results.getString("body"));
            }
        }
    }
}

実行結果

id:1, title:四季が起こる要因
id:2, title:気候と四季の関係
id:3, title:北アメリカの四季
id:4, title:西欧の四季
id:5, title:中欧の四季
id:6, title:北欧の四季
id:7, title:南欧の四季
id:8, title:オセアニアの四季
id:9, title:極東地域の四季
id:10, title:日本列島の四季
id:11, title:四季をテーマにした作品

PreparedStatementを利用してSQLを実行

PreparedStatementインスタンスを取得

Connectionオブジェクトから生成

PreparedStatementインターフェースのインスタンスは、ConnectionクラスのpreparedStatementメソッドで生成します。なお、引数にコンパイル対象のSQLを指定します。引数なしのオーバーロードメソッドはありません。

Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement statement =
    conn.prepareStatement("select id, title from articles where id in (?, ?, ?)");

PreparedStatementインスタンスの主なメソッド

3. PreparedStatementインターフェースの主なメソッドは以下の通りです。

2. Statementインスタンスの主なメソッド
ResultSet executeQuery() PreparedStatementはインスタンスの取得時にSQLを指定してコンパイルするため、executeQueryメソッドは引数ではSQLを指定しない。
ただし親インターフェースのexecuteQuery(String)は実行可能で、その際はSQLのコンパイルは行われない。
int executeUpdate() 上記と同じ理由で引数を持たない。

データ検索

コード例

このコードでもid列とtitle列を抽出してコンソールへ出力しています。ただしwhere句に条件を付けて、idが3 or 4 or 5のレコードを取得します。

PreparedStatement statement =
    conn.prepareStatement("select id, title from articles where id in (?, ?, ?)");
statement.setInt(1, 3);
statement.setInt(2, 4);
statement.setInt(3, 5);

ResultSet results = statement.executeQuery();
while (results.next()) {
    System.out.println(
            "id:" + results.getInt("id") +
            ", title:" + results.getString("title"));
}

createPrepareメソッドの引数のSQL内の「?」バインド変数と言い、任意のパラメータを指定することが出来ます。PreparedStatementのインスタンスには、パラメータの型に応じたsetXXXメソッドが用意されています。

  • PreparedStatementのsetXXXメソッドでパラメータを指定するときのインデックスは1から始まる。0を指定すると実行時にSQLException例外が発生する。

[ソースコード全体はコチラ]

import java.sql.*;

public class JdbcTest {
    public static void main(String[] args) throws SQLException {
        String url = "jdbc:mysql://localhost/test";
        String user = "user";
        String password = "password";

        try (Connection conn = DriverManager.getConnection(url, user, password);) {
            PreparedStatement statement =
                    conn.prepareStatement("select id, title from articles where id in (?, ?, ?)");
            statement.setInt(1, 3);
            statement.setInt(2, 4);
            statement.setInt(3, 5);
        
            ResultSet results = statement.executeQuery();
            while (results.next()) {
                System.out.println(
                        "id:" + results.getInt("id") +
                                ", title:" + results.getString("title"));
            }
        }
    }
}

実行結果

id:3, title:北アメリカの四季
id:4, title:西欧の四季
id:5, title:中欧の四季

データ更新

データの更新(UPDATE)、追加(INSERT)、削除(DELETE)等の、DML文を実行するときは、PreparedStatementのexecuteUpdateメソッドを使用します。このメソッドの戻り値はint型で、変更した行の数を返します。

コード例

PreparedStatement statement = conn.prepareStatement(
        "insert into articles (" +
            "user_id, type, status, title, body, created_at" +
            ") values (?, ?, ?, ?, ?, ?)"
        );
statement.setInt(1, 2);
statement.setInt(2, 1);
statement.setInt(3, 2);
statement.setString(4, "Test-Title");
statement.setString(5, "Test-Body");
statement.setTimestamp(6, new Timestamp(System.currentTimeMillis()));

int count = statement.executeUpdate();
System.out.println("executeUpdate:" + count);

[ソースコード全体はコチラ]

import java.sql.*;

public class JdbcTest {
    public static void main(String[] args) throws SQLException {
        String url = "jdbc:mysql://localhost/test";
        String user = "user";
        String password = "password";

        try (Connection conn = DriverManager.getConnection(url, user, password);) {
            PreparedStatement statement = conn.prepareStatement(
                    "insert into articles (" +
                        "user_id, type, status, title, body, created_at" +
                        ") values (?, ?, ?, ?, ?, ?)"
                    );
            statement.setInt(1, 2);
            statement.setInt(2, 1);
            statement.setInt(3, 2);
            statement.setString(4, "Test-Title");
            statement.setString(5, "Test-Body");
            statement.setTimestamp(6, new Timestamp(System.currentTimeMillis()));
            
            int count = statement.executeUpdate();
            System.out.println("executeUpdate:" + count);
        }
    }
}

実行結果

executeUpdate:1

テーブルを確認すると、JDBCで設定した内容で追加されていることが分かります。

コメント

このブログの人気の投稿

docker-compose up で proxyconnect tcp: dial tcp: lookup proxy.example.com: no such host

docker-compose で起動したweb、MySQLに接続できない事象

【PHP】PHP_CodeSnifferを使う(コーディングルールのカスタマイズ)