SJ blog
Java
Z

信頼度ランク

S 公式ソース確認済み
A 成功実績多数・失敗例少数
B 賛否両論
C 動作未確認・セキュリティリスク高
Z 個人所感

JavaのJDBC接続トラブルシューティング完全ガイド

JDBC接続の基本から、ClassNotFoundException/SQLException/タイムアウトなどよくあるエラーの原因と解決方法、コネクションプールの正しい使い方まで解説します。

一言結論

JDBCトラブルの大半はドライバJARの欠如・URL誤記・コネクションリークの3つに集約され、try-with-resourcesでConnectionを必ず閉じることがコネクションプール枯渇を防ぐ最重要対策だ。

JDBC 接続の基本

String url = "jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=Asia/Tokyo";
String user = "root";
String password = "password";

try (Connection conn = DriverManager.getConnection(url, user, password)) {
    System.out.println("接続成功");
} catch (SQLException e) {
    System.err.println("接続失敗: " + e.getMessage());
}

よくあるエラーと解決方法

1. ClassNotFoundException

java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver

原因: JDBCドライバのJARがクラスパスにない。

解決(Maven):

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.1.0</version>
</dependency>

他のデータベース:

<!-- PostgreSQL -->
<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.6.0</version>
</dependency>

<!-- H2(インメモリDB、開発・テスト用) -->
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>2.2.224</version>
    <scope>test</scope>
</dependency>
com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure

原因と対処:

原因対処
MySQL サーバーが起動していないサービスを起動する
ポート番号が違う`netstat -an
ファイアウォールがブロックポートを開放する
ホスト名が間違っているURL を確認
SSL が必要useSSL=true または requireSSL=true

3. Access denied

java.sql.SQLException: Access denied for user 'root'@'localhost'

解決:

-- MySQLで権限を確認
SHOW GRANTS FOR 'root'@'localhost';

-- 権限を付与
GRANT ALL PRIVILEGES ON mydb.* TO 'root'@'localhost';
FLUSH PRIVILEGES;

4. Too many connections

com.mysql.cj.jdbc.exceptions.CommunicationsException: ... Too many connections

原因: 接続を閉じずにリークしている。

確認:

SHOW STATUS LIKE 'Threads_connected';
SHOW PROCESSLIST;

解決: 接続を確実に閉じる(try-with-resources):

// NG: 接続を閉じていない
Connection conn = DriverManager.getConnection(url, user, pass);
Statement stmt = conn.createStatement();
stmt.executeQuery(sql);
// → conn が閉じられない

// OK: try-with-resources
try (Connection conn = DriverManager.getConnection(url, user, pass);
     Statement stmt = conn.createStatement();
     ResultSet rs = stmt.executeQuery(sql)) {
    while (rs.next()) {
        System.out.println(rs.getString("name"));
    }
}

5. タイムアウト

com.mysql.cj.exceptions.CJCommunicationsException: The last packet sent successfully...

長時間未使用の接続が切れている問題です。

解決(接続URLにタイムアウト設定):

jdbc:mysql://localhost:3306/mydb?connectTimeout=5000&socketTimeout=30000

コネクションプールを使う場合(HikariCP):

HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("root");
config.setPassword("password");
config.setMaximumPoolSize(10);
config.setConnectionTimeout(30000);
config.setIdleTimeout(600000);
config.setMaxLifetime(1800000);
config.setKeepaliveTime(300000);  // 5分ごとにkeepalive

HikariDataSource ds = new HikariDataSource(config);

6. SQLState の読み方

SQLExceptiongetSQLState() で原因が分かります:

SQLState意味
08001接続確立失敗
08S01通信リンク障害
42000構文エラー
23000一意性制約違反
40001デッドロック
} catch (SQLException e) {
    System.err.println("SQLState: " + e.getSQLState());
    System.err.println("ErrorCode: " + e.getErrorCode());
    System.err.println("Message: " + e.getMessage());
}

PreparedStatement でSQLインジェクションを防ぐ

// NG: SQLインジェクション脆弱性
String sql = "SELECT * FROM users WHERE name = '" + name + "'";

// OK: PreparedStatement
String sql = "SELECT * FROM users WHERE name = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
    ps.setString(1, name);
    try (ResultSet rs = ps.executeQuery()) {
        while (rs.next()) {
            System.out.println(rs.getString("email"));
        }
    }
}

コネクションプール(HikariCP)のモニタリング

// JMX でプールの状態を確認
HikariPoolMXBean poolMXBean = hikariDataSource.getHikariPoolMXBean();
System.out.println("アクティブ接続: " + poolMXBean.getActiveConnections());
System.out.println("アイドル接続: " + poolMXBean.getIdleConnections());
System.out.println("待機スレッド: " + poolMXBean.getThreadsAwaitingConnection());

まとめ

エラーまず確認すること
ClassNotFoundExceptionJARがクラスパスにあるか
Communications link failureDBサーバーが起動しているか、URLが正しいか
Access deniedユーザー名/パスワード/権限
Too many connections接続リーク(try-with-resources を使っているか)
タイムアウトコネクションプールの keepalive 設定

現代の Java アプリでは DriverManager を直接使わず、HikariCP などのコネクションプールを通じて接続するのが標準的です。