到達点は、値をSQLへ安全に渡し、複数の更新をまとめることです。前提は第08・11回です。
データベースにもルールを置く
テーブルは同じ項目を持つ行の集まりです。主キーは行を識別し、NOT NULLやCHECKは保存できる値を制限します。アプリ側だけの検査では、別の書き込み経路から不正な値が入る可能性があります。
実習では第11回のpom.xmlのdependenciesに、次のH2依存を追加します。メモリ上のDBなので既存のファイルは変更しません。
<dependency>
<groupId>com.h2database</groupId><artifactId>h2</artifactId><version>2.3.232</version>
</dependency>
src/main/java/study/DbDemo.java を作ります。
package study;
import java.sql.*;
public class DbDemo {
public static void main(String[] args) throws SQLException {
try (Connection db = DriverManager.getConnection("jdbc:h2:mem:study")) {
try (Statement s = db.createStatement()) {
s.execute("CREATE TABLE lessons(id INT PRIMARY KEY, title VARCHAR(200) NOT NULL)");
}
db.setAutoCommit(false);
try (PreparedStatement insert = db.prepareStatement(
"INSERT INTO lessons(id,title) VALUES (?,?)")) {
insert.setInt(1, 1);
insert.setString(2, "Java's SQL");
insert.executeUpdate();
db.commit();
} catch (SQLException e) {
db.rollback();
throw e;
}
try (PreparedStatement query = db.prepareStatement(
"SELECT title FROM lessons WHERE id = ?")) {
query.setInt(1, 1);
try (ResultSet rows = query.executeQuery()) {
while (rows.next()) System.out.println(rows.getString("title"));
}
}
}
}
}
実行は mvn compile org.codehaus.mojo:exec-maven-plugin:3.5.0:java -Dexec.mainClass=study.DbDemo です。出力は Java's SQL です。値に引用符があっても、プレースホルダへ渡せばSQLの構造と混ざりません。
原子性と検索の費用
commitは変更を確定し、rollbackは未確定の変更を取り消します。二つの残高を更新する処理なら、片方だけ成功した状態を避けるため同じトランザクションへまとめます。ただし同時更新の競合まで自動的に全部解決するわけではありません。分離レベルや更新条件も設計対象です。
インデックスは検索を助けますが、保存場所と更新費用が必要です。頻繁な検索条件を実行計画で確認して追加します。外部キー、JOIN、ORDER BY、LIMITも次に試しましょう。並び順はORDER BYがなければ保証に頼れません。
練習と解答
練習:同じ主キーを二回挿入し、同じトランザクション内の最初の挿入も取り消されるか確認してください。
解答の要点:最初の挿入の後、commit前に同じIDを挿入します。重複エラーを受けてrollbackし、件数が0なら意図どおりです。先にcommitしてしまうと最初の行は取り消されません。
公式資料
Java全20回の目次 | 前の回 | 次の回