解説 · セクション 1
interface を使いこなす
JDBC で「いきなり要求される」interface 変数の感覚を、身近な例えと図で押さえます。読み終わったら問題に挑戦してください。
身近に置き換えると
データベース操作を「銀行の窓口」でのやり取りに置き換えてみましょう。あなたが銀行で振り込みをしたいとき、まずは「総合案内」に行き、要件を伝えて「担当窓口」に案内してもらいます。次に、担当窓口で「振込用紙」をもらい、そこに記入して提出すると、最後に「明細書」を受け取ります。
A銀行に行っても、B銀行に行っても、この「案内→窓口→用紙→明細」という手順(ルール)は同じです。Javaのデータベース接続(JDBC)もこれと全く同じで、データベースの種類が変わっても、共通のルール(interface)に沿って操作を進めていきます。
3 行でまとめると
- interface は
newできないため、専用の案内係(DriverManager)から実体を受け取る。 - 戻り値はすべて interface 型(
Connection,PreparedStatement,ResultSet)の変数で順番に受け取っていく。 - interface 越しに操作するため、裏のデータベース(実装)が変わっても Java の呼び出しコードは変わらない。
図で見ると
classDiagram
class DriverManager {
+getConnection() Connection
}
class Connection {
<>
+prepareStatement() PreparedStatement
}
class PreparedStatement {
<>
+executeQuery() ResultSet
}
class ResultSet {
<>
}
DriverManager ..> Connection : 戻り値として渡す
Connection ..> PreparedStatement : 戻り値として渡す
PreparedStatement ..> ResultSet : 戻り値として渡す
案内係(DriverManager)から始まり、次々と interface の戻り値を受け取ってバトンリレーのように処理を進めていくのが JDBC の基本構造です。
順を追って理解する
1. interface は new できない
Javaのルールとして、interface はあくまで「操作の約束事」であり、実体がないため new Connection() のように直接生み出すことはできません。実体を作るには、代わりに作ってくれる別の仕組みが必要です。
2. 案内係(ファクトリ)から実体をもらう
そこで登場するのが DriverManager クラスです。このクラスの getConnection() は static メソッド(クラスに直接お願いできる案内係)になっており、これを呼び出すことで Connection(担当窓口)の実体をもらいます。受け取る左辺の変数は、interface 型である Connection 型で宣言します。
3. 窓口から用紙をもらう(prepareStatement の位置づけ)
担当窓口(Connection)につながったら、次は「こんなSQLを実行したい」と伝えて準備をします。Connection の prepareStatement() メソッドを呼び出すと、SQLの準備用紙である PreparedStatement 型の戻り値がもらえます。これも interface 型の変数で受け取ります。
4. 実行して結果をもらう
準備用紙(PreparedStatement)に条件などを書き込んだら、executeQuery() メソッドで実行します。すると、データベースから検索結果が ResultSet 型(明細書)として返ってきます。これもやはり interface です。
5. なぜすべて interface なのか?(実装の差し替え)
MySQL、PostgreSQL、Oracleなど、データベースによって裏側の通信の仕組み(実装)はバラバラです。しかし、Java側がすべて Connection や PreparedStatement といった共通の interface 越しに操作するようにしておけば、接続先のデータベースを変えても、Javaのコードを一切書き換える必要がなくなります。これを「実装の差し替え」と呼びます。
応用ではこう書く
// 1. 案内係 (DriverManager) から 担当窓口 (Connection) をもらう
// ※ getConnection は static メソッドなので、クラス名から直接呼び出します
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/mydb", "user", "pass");
// 2. 窓口 (Connection) から 準備用紙 (PreparedStatement) をもらう
// ※ ここで実行したいSQLの骨組みを渡します
PreparedStatement pstmt = conn.prepareStatement("SELECT name FROM users WHERE id = ?");
// 3. 準備用紙に具体的な値を書き込む
pstmt.setInt(1, 100);
// 4. 実行して、結果の明細 (ResultSet) をもらう
ResultSet rs = pstmt.executeQuery();
// 5. 明細 (ResultSet) からデータを読み取る
while (rs.next()) {
System.out.println(rs.getString("name"));
}
// ※ 左辺の型 (Connection, PreparedStatement, ResultSet) はすべて interface です。
このように、自分で new をするのではなく、メソッドの戻り値として interface を受け取り、その interface のメソッドを呼んでさらに次の interface を受け取る、という流れでコードを書きます。
よくある誤解
誤解: Connection conn = new Connection(); と書いてしまう
正しくは: Connection は interface なので new できません。必ず DriverManager.getConnection(...) のように、実体を作って返してくれるメソッド(ファクトリ)の戻り値として受け取ります。
誤解: データベースの種類(MySQLやOracleなど)ごとに、Javaのメソッドの呼び方を変えなければならない
正しくは: 変えなくて大丈夫です。左辺の変数をすべて共通の interface(Connection など)で宣言しているため、最初の getConnection() で渡す接続先URLを変えるだけで、その後の prepareStatement や executeQuery といった呼び出しコードは全く同じまま動きます。
つまずいたら
このトピックで詰まったら基礎復習へ: 章 4 インターフェース