晴耕雨読

working in the fields on fine days and reading books on rainy days

[Java] DB接続とSQL実行

JavaでDBと接続してSQLを発行する方法

ここではMySQLに登録したデータを抽出する例を示します。 事前に用意するテーブルとデータを作るSQLを以下に示します。

drop table fruits;
create table fruits (
  id int not null,
  name varchar(20),
  price int,
  primary key (id)
);
insert into fruits (id, name, price) values
  (1,'りんご', 200),
  (2,'みかん', 250),
  (3,'なし', 300);
mysql> select * from fruits;
+----+--------+-------+
| id | name   | price |
+----+--------+-------+
|  1 | りんご |   200 |
|  2 | みかん |   250 |
|  3 | なし   |   300 |
+----+--------+-------+

SELECTの結果の取得 (executeQuery)

String url = "jdbc:mysql://localhost:3306/sample?serverTimezone=JST";
try (Connection conn = DriverManager.getConnection(url, "dbuser", "password");
        Statement stmt = conn.createStatement()) {
    ResultSet result = stmt.executeQuery("SELECT * FROM fruits");
    while (result.next()) {
        System.out.printf("%d: %s %d円\n",
            result.getInt("id"), result.getString("name"), result.getInt("price"));
    }
    // => 1: りんご 200円
    // => 2: みかん 250円
    // => 3: なし 300円
} catch (SQLException e) {
    e.printStackTrace();
}

UPDATEの実行 (executeUpdate)

結果を返さない(select以外の)SQL文を発行するときは executeUpdate を使います。

String url = "jdbc:mysql://localhost:3306/sample?serverTimezone=JST";
String sql = "UPDATE fruits SET price=? WHERE name=?";
try (Connection conn = DriverManager.getConnection(url, "dbuser", "password");
        PreparedStatement stmt = conn.prepareStatement(sql)) {
    // パラメータのバインド
    stmt.setInt(1, 500);
    stmt.setString(2, "りんご");
    System.out.println(stmt.executeUpdate()); // => 1
} catch (SQLException e) {
    e.printStackTrace();
}
mysql> select * from fruits;
+----+--------+-------+
| id | name   | price |
+----+--------+-------+
|  1 | りんご |   500 |
|  2 | みかん |   250 |
|  3 | なし   |   300 |
+----+--------+-------+

トランザクションのコミットとロールバック (commit, rollback)

insert時に意図的に主キーが重複する値を指定してロールバックを発生させる例:

String url = "jdbc:mysql://localhost:3306/sample?serverTimezone=JST";
String sql = "UPDATE fruits SET price=? WHERE name=?";
try (Connection conn = DriverManager.getConnection(url, "dbuser", "password");
        PreparedStatement stmt = conn.prepareStatement(sql)) {
    conn.setAutoCommit(false);
    try {
        // update文:この更新はコミットされるまでDBに反映されない
        stmt.executeUpdate("UPDATE fruits SET price=999 WHERE name='りんご'");
        // insert文:主キーidが重複するレコードを挿入
        stmt.executeUpdate("INSERT INTO fruits(id, name, price) VALUES (1, 'すいか', 1000)");
        // コミット
        conn.commit();
    } catch (SQLException e) {
        // ロールバック
        conn.rollback();
        System.out.println("ロールバック発生:" + e.getMessage());
        // => ロールバック発生:Duplicate entry '1' for key 'fruits.PRIMARY'
    }
} catch (SQLException e) {
    e.printStackTrace();
}

SELECTの結果のカーソルを移動

カーソル移動ができるようにするためには、TYPE_SCROLL_INSENSITIVE または TYPE_SCROLL_SENSITIVE を指定する必要があります。

カーソル種類 (createStatementの第一引数):

  • TYPE_FORWARD_ONLY : カーソルは順方向にしか移動できない(next()しか使えない)
  • TYPE_SCROLL_INSENSITIVE : 任意のカーソル移動が可能。他によるデータ変更を反映しない
  • TYPE_SCROLL_SENSITIVE : 任意のカーソル移動が可能。他によるデータ変更を反映する

カーソル移動方法:

  • absolute(int) : 指定した行番号にカーソルを移動する(絶対位置に移動する)
  • afterLast() : 最終行の後ろにカーソルを移動する
  • beforeFirst() : 先頭行の前にカーソルを移動する
  • first() : 先頭行にカーソルを移動する
  • last() : 最終行にカーソルを移動する
  • next() : 次の行にカーソルを移動する
  • previous() : 前の行にカーソルを移動する
  • relative(int) : 指定した行数(負数もあり)だけカーソルを移動する(相対位置に移動する)
String url = "jdbc:mysql://localhost:3306/sample?serverTimezone=JST";
try (Connection conn = DriverManager.getConnection(url, "dbuser", "password");
        Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
                                              ResultSet.CONCUR_READ_ONLY)) {

    ResultSet result = stmt.executeQuery("SELECT * FROM fruits ORDER BY id");

    // 最初のレコードを取得
    result.first();
    System.out.printf("%d: %s %d円\n",
        result.getInt("id"), result.getString("name"), result.getInt("price"));
    // => 1: りんご 200円

    // 最後のレコードを取得
    result.last();
    System.out.printf("%d: %s %d円\n",
        result.getInt("id"), result.getString("name"), result.getInt("price"));
    // => 3: なし 300円

} catch (SQLException e) {
    e.printStackTrace();
}