1
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?

【Java用語、結局なんだっけ? #2】DB接続編 ― JDBC・ドライバー・コネクション・コネクションプール・トランザクション

1
Posted at

はじめに

株式会社Good Labでエンジニアをしている コータロー です。
日々、Java・SQL・Gitなどの技術情報や、新人エンジニア向けの学習ノウハウ、
AI活用についての情報を発信しています。

Good Labについて気になった方は、コーポレートサイトもぜひご覧ください。
コーポレートサイト

「Java用語、結局なんだっけ?」シリーズの第2回です。

テーマ
#1 環境・基盤編
#2(本記事) DB接続編
#3 Web/サーバー編
#4 例外・スレッド編
#5 モダンJava編
#6 フレームワーク編
#7 ビルド・運用編

今回は DB接続編 です。「JDBC」「ドライバー」「コネクション」「コネクションプール」「データソース」「トランザクション」を一気に整理します。


この記事のゴール

  • JDBC が 仕様 であり、ドライバー が実装である関係を説明できる
  • コネクション・コネクションプール・データソースの違いを説明できる
  • トランザクションの基本(コミット・ロールバック)を説明できる

全体像:JavaアプリがDBに繋がるまで

[Javaアプリ]
    ↓ JDBCのAPIを呼ぶ(仕様)
[JDBC API]   ← java.sql パッケージ
    ↓
[JDBCドライバー]  ← MySQL Connector/J、PostgreSQL JDBC Driver等(実装)
    ↓ DBプロトコルで通信
[DBサーバー]  ← MySQL、PostgreSQL、Oracle等

そして実務では、コネクションプールデータソース が間に挟まります。

[Javaアプリ]
    ↓
[データソース(DataSource)]  ← 接続管理のインターフェース
    ↓
[コネクションプール]          ← 既存接続を再利用
    ↓
[JDBCドライバー]
    ↓
[DBサーバー]

これらの用語を6つに分けて解説します。


① JDBC ― 「Java からDBを操作する標準仕様」

一言で言うと

Java から DB を操作するための標準APIの仕様です。
ConnectionStatementResultSet などのインターフェースが定義されています。

正式名称は Java Database Connectivity

重要なポイント

JDBCは 「仕様」であって「実装」ではありません

JDBC(仕様)        ← java.sql.Connection, java.sql.PreparedStatement など
   ↓
JDBCドライバー(実装) ← MySQL用、PostgreSQL用、Oracle用 など別々

「Javaから何のDBにでも接続できる」のは、各DBベンダーが JDBC仕様に従ったドライバー を提供しているからです。

コード例

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

public class JdbcDemo {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/sampledb";
        String user = "root";
        String password = "password";

        try (Connection conn = DriverManager.getConnection(url, user, password);
             PreparedStatement stmt = conn.prepareStatement("SELECT id, name FROM users WHERE id = ?")) {

            stmt.setInt(1, 1);

            try (ResultSet rs = stmt.executeQuery()) {
                while (rs.next()) {
                    int id = rs.getInt("id");
                    String name = rs.getString("name");
                    System.out.println("ID=" + id + " name=" + name);
                }
            }
        } catch (SQLException e) {
            System.err.println("DB操作失敗: " + e.getMessage());
        }
    }
}

import文を見れば分かるように、ConnectionPreparedStatementResultSetjava.sql パッケージ(JDBC仕様)に属しています。

よくある誤解

  • 「JDBC は MySQL のためのもの」:JDBCは仕様で、MySQLでもPostgreSQLでもOracleでも使える共通API。
  • 「JDBCドライバーをインストールすればDB操作ができる」:ドライバーは「接続部品」。実際にDBへの読み書きをするのはDBサーバー側。

② JDBCドライバー ― 「JDBC仕様の実装」

一言で言うと

**JDBC仕様を各DBベンダーが実装した「接続部品」**です。
通常はJARファイルとして提供されます。

種類

DB ドライバー名 Maven依存例
MySQL MySQL Connector/J mysql:mysql-connector-java
PostgreSQL PostgreSQL JDBC Driver org.postgresql:postgresql
Oracle Oracle JDBC Driver com.oracle.database.jdbc:ojdbc11
SQL Server Microsoft JDBC Driver com.microsoft.sqlserver:mssql-jdbc
H2(インメモリ) H2 Database com.h2database:h2

何をしている?

  • JDBC仕様の ConnectionPreparedStatement 等を 具象クラスとして実装
  • DB独自のネットワークプロトコル(例:MySQLバイナリプロトコル)を扱う
  • JavaのオブジェクトとDBのデータ型を変換(java.sql.DateDATETIME 等)

ドライバーの読み込み(昔と今)

Java 6以前:明示的に Class.forName でドライバーを読み込む必要があった

// 昔のコード
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection(url, user, password);

Java 6以降:JARをクラスパスに置けば、DriverManager が自動で見つけてくれる(SPI機構)

// 現代のコード(Class.forName 不要)
Connection conn = DriverManager.getConnection(url, user, password);

たまに「Class.forName を書け」と古い記事に書かれていますが、現代では基本不要です。

よくある誤解

  • 「JDBCドライバーはJDKに含まれている」:含まれていない。別途インストール(pom.xmlやbuild.gradleに記述)が必要。
  • 「ドライバーを変えればDBが変わる」:URLとドライバーを差し替えれば、コード本体はほぼそのまま動く(これがJDBCの利点)。

③ コネクション(Connection) ― 「DBへの1本の通信回線」

一言で言うと

**Javaアプリ ⇔ DBサーバー間の1本の「電話線」**のようなものです。
このコネクションを使ってクエリを送り、結果を受け取ります。

特徴

  • 重い:コネクションを作るには TCP接続+認証+セッション確立 が必要(数十〜数百ミリ秒)
  • 限りがある:DBサーバー側に「同時接続数の上限」がある(MySQLデフォルト151)
  • 状態を持つ:トランザクション、文字コード、自動コミット設定など

コネクションのライフサイクル

1. DriverManager.getConnection(...)  ← 接続を開く(重い処理)
2. クエリ実行(SELECT / INSERT / UPDATE / DELETE)
3. conn.close()                       ← 接続を閉じる

毎回 getConnectionclose を繰り返すと、接続コストが膨大 になります。
これを解決するのが次に説明する コネクションプール です。

よくある誤解

  • 「コネクションは何個でも作っていい」:DBサーバーの上限に達すると 「Too many connections」エラーで本番障害が起きる。
  • 「conn.close() しなくても、しばらくしたら勝手に閉じる」:閉じない。確実に閉じる必要 がある(try-with-resourcesが推奨)。

④ コネクションプール ― 「使い回しのプール」

一言で言うと

事前に複数のコネクションを作っておき、必要な時に貸し出す仕組みです。
プール=水泳プールではなく、「貯水池」のイメージ。

なぜ必要か

毎回コネクションを作ると遅すぎる。だから 「最初にまとめて作って、使い終わったら返してもらう」 方式にする。

[コネクションプール]
   ┌──────┬──────┬──────┬──────┐
   │ conn1 │ conn2 │ conn3 │ conn4 │  ← 起動時に4本作成
   └──────┴──────┴──────┴──────┘
                          ↑
                  リクエストAが借りる
                  処理後、プールに返却
                  次のリクエストBが再利用

主なコネクションプール実装

名前 概要
HikariCP 業界標準。高速・軽量。Spring Bootのデフォルト
Apache DBCP Apacheの歴史ある実装。Tomcatに同梱
C3P0 古くからあるOSS。最近は採用減

新規案件でコネクションプールを選ぶなら、HikariCPの一択です。

設定例(Spring Boot)

spring.datasource.url=jdbc:mysql://localhost:3306/sampledb
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.connection-timeout=30000

maximum-pool-size=10 で「同時に10本までコネクションを保持」という意味です。

よくある誤解

  • 「プールサイズは大きいほど高速」:違う。DB側の上限を超えると逆に詰まる。CPU数や同時接続要件から適切なサイズを計算する。
  • 「コネクションプールを使えば conn.close() しなくていい」:違う。close() は呼ぶ。ただし 実際には閉じずに、プールに返却 されるという挙動。

⑤ データソース(DataSource) ― 「接続管理の抽象インターフェース」

一言で言うと

Connection を取得するための標準インターフェースです。
javax.sql.DataSource として定義されています(javax.sql は Java SE 側のAPIのため、Jakarta EE の名前空間変更の対象外。今でも javax.sql.DataSource のままです)。

DriverManager との違い

観点 DriverManager DataSource
接続取得 毎回新規作成 プールから貸し出し可能
設定 コード内にURL等を埋め込む 外部設定(プロパティ等)で管理
透過性 DB依存が見える 利用側はDB種類を意識しない
推奨度 レガシー・サンプル用 業務コードの標準

コード例

// 推奨:DataSourceを使う
@Autowired
private DataSource dataSource;

public void findUser(long id) {
    try (Connection conn = dataSource.getConnection();
         PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?")) {
        // ...
    }
}

Spring Boot を使っていると、DataSource の実体(HikariCP等)は 自動で組み立てられて注入されます
開発者は 接続URLや認証情報を application.properties に書くだけ でOK。

よくある誤解

  • 「DataSource = データベース」:違う。接続を提供する仕組み。DBそのものではない。
  • DriverManager で十分」:単体テストやサンプルでは十分。だが業務コードではプール対応の DataSource が必須。

⑥ トランザクション ― 「複数SQLをまとめて成功/失敗させる単位」

一言で言うと

「全部成功するか、全部失敗するか」を保証する処理の単位です。
銀行送金(口座A→口座B)のように、途中で止まると不整合が出る処理 に必要。

例:送金処理

1. 口座Aから1万円引く
2. 口座Bに1万円足す

もし手順1だけ成功して手順2が失敗したら、1万円が消滅 します。
トランザクションを使えば、「両方成功したら確定」「途中で失敗したら全部巻き戻し」を実現できます。

コード例

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

public class TransactionDemo {
    public static void transferMoney(long fromId, long toId, int amount) {
        String url = "jdbc:mysql://localhost:3306/bank";

        try (Connection conn = DriverManager.getConnection(url, "user", "pass")) {
            conn.setAutoCommit(false);  // 自動コミットOFF

            try (PreparedStatement withdraw = conn.prepareStatement(
                    "UPDATE accounts SET balance = balance - ? WHERE id = ?");
                 PreparedStatement deposit = conn.prepareStatement(
                    "UPDATE accounts SET balance = balance + ? WHERE id = ?")) {

                withdraw.setInt(1, amount);
                withdraw.setLong(2, fromId);
                withdraw.executeUpdate();

                deposit.setInt(1, amount);
                deposit.setLong(2, toId);
                deposit.executeUpdate();

                conn.commit();   // 両方成功した場合のみ確定
            } catch (SQLException e) {
                conn.rollback();  // どちらかが失敗したら全部巻き戻し
                throw e;
            }
        } catch (SQLException e) {
            System.err.println("送金失敗: " + e.getMessage());
        }
    }
}

ポイント:

  • setAutoCommit(false):自動コミットを止める(明示的に commit するまで確定しない)
  • commit():すべて成功した時点で確定
  • rollback():失敗時に全部巻き戻し

Spring Boot ではアノテーション1個で済む

業務コードでJDBCを直接書くことはほぼなく、@Transactional アノテーション1個でトランザクション制御できます。

@Transactional
public void transferMoney(long fromId, long toId, int amount) {
    accountRepository.withdraw(fromId, amount);
    accountRepository.deposit(toId, amount);
}

メソッドが正常終了したら commit、例外が発生したら rollback が自動で実行されます。

ACIDの4特性(用語として知っておく)

特性 一言で
Atomicity(原子性) 「全部成功 or 全部失敗」
Consistency(一貫性) 整合性が保たれる
Isolation(独立性) 並行実行が互いに干渉しない
Durability(永続性) コミットしたら消えない

よくある誤解

  • 「トランザクションは必ず必要」:違う。1個のSQLしか実行しない ならトランザクションは不要(自動コミットで十分)。
  • 「rollback したらアプリも止まる」:違う。DBの変更が巻き戻るだけ。Javaコード上の処理は普通に続く。

用語まとめ早見表

用語 一言で 関係性
JDBC DB接続の仕様 java.sql パッケージ
JDBCドライバー JDBC仕様の実装(DBベンダー製) JARで配布、クラスパスに追加
Connection DBへの1本の接続 重い、状態を持つ
コネクションプール 接続を事前に作って使い回す仕組み HikariCPが標準
DataSource 接続取得の抽象インターフェース 業務コードはこちらを使う
トランザクション 全部成功 or 全部失敗」の単位 setAutoCommit(false) + commit/rollback

現場あるある誤解集

❌ 誤解 ⭕ 正しい理解
「JDBC = MySQLのこと」 JDBCは仕様。MySQL以外でも同じAPIで操作できる
「ドライバーはOSにインストールするもの」 JAR形式で配布、Mavenで依存追加するもの
「コネクションは作りっぱなしでOK」 確実にcloseする。DB側の上限に達すると本番障害
「コネクションプールサイズは大きいほど良い」 大きすぎるとDB側が詰まる。CPU数等から計算
DriverManager で本番運用OK」 プール未対応で遅い。DataSource を使う
@Transactional は何にでも付ければOK」 内部メソッド呼び出しでは効かない等の罠あり
「1個のSQLでもトランザクションが必要」 自動コミットで十分。複数SQLをまとめる時だけ必要

演習問題

問題1:JDBCとドライバーの関係 ⭐

次の文章の空欄を埋めてください。

「JDBCは ___ であって、実装ではない。各DBベンダー(MySQL、PostgreSQL等)が JDBC___ を提供している。Java側のコードは ___ パッケージのAPIを呼ぶだけで、DBの種類によらず動く。」

模範解答

「JDBCは 仕様 であって、実装ではない。各DBベンダー(MySQL、PostgreSQL等)が JDBCドライバー を提供している。Java側のコードは java.sql パッケージのAPIを呼ぶだけで、DBの種類によらず動く。」

ポイント:「仕様(インターフェース)と実装(具象クラス)の分離」がJDBCの設計の肝。これによりJavaコードがDB非依存になります。


問題2:コネクションプール ⭐

コネクションプールについて、間違っている 説明はどれですか?

  • A. 起動時にあらかじめ複数の接続を作っておく
  • B. 接続を使い終わったら破棄して、次の処理で新規作成する
  • C. HikariCPがSpring Bootのデフォルト
  • D. プールサイズは大きすぎるとDB側が詰まる
模範解答

正解:B

解説

  • B はNG:コネクションプールは「使い終わったら 返却して再利用 」する仕組み。破棄しません。conn.close() は呼びますが、実体は「プールに返す」動作になります。
  • A、C、D は正しい

ポイント:「conn.close() が呼ばれた時に本当に物理的に閉じるかどうか」は、DataSource の実装次第。プール経由なら返却、DriverManager 経由なら本物のclose。


問題3:トランザクション ⭐

次の処理にトランザクションが必要なのはどれですか?(複数選択可)

  • A. ユーザー1件をINSERTする
  • B. 商品リストをSELECTする
  • C. 注文を作成し、在庫を1減らす
  • D. ログテーブルに1件INSERTする
  • E. 口座Aから1000円引き、口座Bに1000円足す
模範解答

正解:C と E

解説

  • C はトランザクションが必要:「注文作成」と「在庫減算」が両方成功しないと不整合(注文だけ作って在庫が減らない、等)
  • E はトランザクションが必要:典型的な「全部成功 or 全部失敗」のケース
  • A、B、D は 単一のSQL なので、自動コミットで十分

ポイント:トランザクションが必要かは「複数のSQLが論理的にひとまとまり か」で判断します。1個ずつ独立しているなら不要です。


まとめ

DB接続まわりの6用語のおさらいです。

  1. JDBC:DB接続の標準仕様java.sql
  2. JDBCドライバー:JDBC仕様の実装(DBベンダー製、JAR配布)
  3. Connection:DBへの1本の接続(重い・有限)
  4. コネクションプール:接続の使い回し機構(HikariCPが標準)
  5. DataSource:接続取得の抽象インターフェース(業務コードはこれを使う)
  6. トランザクション:「全部成功 or 全部失敗」の単位

新人のうちに「仕様と実装の分離」「重い接続をどう使い回すか」という設計思想を掴んでおくと、Spring Boot や JPA に進んでも迷いません。


次回予告

次回(#3)は Web/サーバー編 です。

  • サーブレット・JSP・Tomcatの関係
  • WARファイルとは何か
  • フィルタの役割
  • ステートフル/ステートレスの違い

を、現場で出会う形式で解説します。


参考


@kotaro_ai_lab
AI活用や開発効率化について発信しています。フォローお気軽にどうぞ!

1
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
1
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?