0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PreparedStatementのnullチェックは本当に必要か?仕様から読み解く現代のDB作法

0
Posted at

はじめに

JavaでJDBCを扱う際、古いサンプルコードでは必ずと言っていいほど if (ps != null) ps.close(); という記述が登場します。
「Connectionが確立していれば、prepareStatementがnullを返すことはないのでは?」
「単体テストでこのnullパスを通すのは不可能に近いのでは?」
こうした疑問を、Javaの言語仕様(JLS)と公式APIドキュメントをベースに解消します。

1. なぜ「nullチェック」という慣習が生まれたのか

結論から言うと、Java 6以前try-catch-finally 構造における「二次災害(NPE)」を防ぐための防御策でした。

例外発生時の挙動(言語仕様)

PreparedStatement ps = null; 
try {
    // ここで例外(SQLException等)が発生すると...
    ps = conn.prepareStatement(sql); 
    // ↑ この代入(ps = ...)自体が行われない!
} finally {
    // psは初期値の null のままここに到達する
    ps.close(); // ここで NullPointerException が発生し、元の例外が書き換わってしまう
}

2. 単体テストにおける「カバレッジ地獄」

このガード句を律儀に書くと、単体テスト(JUnit等)で以下の問題に直面します。

  1. 再現の困難さ: JDBCドライバが正常なら、conn が有効な限り prepareStatement はインスタンスを返します。

  2. 不自然なモック: 「例外を投げずに null を返す」という、実際のドライバではあり得ない挙動を Mockito 等で無理やり作る必要があります。

「起こり得ないパターンのために、テストコードを複雑にする」 のは保守性の観点からアンチパターンと言えます。

3. 現代の正解:try-with-resources

Java 7で導入された try-with-resources 構文を使えば、これらの問題は根本から解消されます。


try (Connection conn = getConnection();
     PreparedStatement ps = conn.prepareStatement(sql)) {
    // 実行処理
} catch (SQLException e) {
    // 例外処理
}

仕様上のメリット
暗黙のnullチェック: コンパイル時に生成されるコードには、自動的に if (ps != null) 相当のチェックが含まれます。

カバレッジの適正化: 開発者が if 文を書かないため、テスト不能な分岐に悩まされることがなくなります。

4. トランザクション制御(ロールバック)との共存

「try-with-resources は自動クローズされるから、明示的なロールバックができないのでは?」という懸念がありますが、リソースの宣言順序を理解すれば安全に記述可能です。


try (Connection conn = getConnection()) {
    conn.setAutoCommit(false); 

    // Connectionを活かしたまま、Statementをtry-with-resourcesで管理
    try (PreparedStatement ps = conn.prepareStatement(sql)) {
        ps.executeUpdate();
        conn.commit(); 
    } catch (SQLException e) {
        conn.rollback(); // psは閉じられるが、connはまだ生きているのでロールバック可能!
        throw e;
    }
}

クローズの順序(言語仕様)
JLS(Java Language Specification)により、リソースは 「宣言された順序の逆」 でクローズされます。
上記コードでは psconn の順で閉じられるため、catch ブロック内では conn はまだ有効です。

5. 結論

PreparedStatement の null チェックは、古い finally 構文特有の課題に対する回答だった。

現代の Java では try-with-resources を使うことで、この不毛なチェックとテスト地獄から解放される。

トランザクション制御も、リソースの入れ子構造を理解すれば安全に実装できる。

参考文献

Oracle Java SE Documentation : try-with-resources

Connection (Java Platform SE 8)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?