Lesson 8
DB接続
目次
Lesson 8
Chapter 1
JDBCとは
データベース(DB)は、情報を効率的に管理するための仕組みです。私たちが日々使用するアプリケーションやWebサイトは、様々なデータを必要としています。例えば、顧客情報、商品情報、注文情報などです。これらのデータは、単にファイルやExcelなどの表計算ソフトに保存するだけでは、データの整合性や検索効率などの問題が生じることがあります。データベースは、これらのデータを一元管理することができます。つまり、複数のアプリケーションやWebサイトで使用されるデータを集約して保存することができるため、データの整合性が保たれ、検索も効率的に行えます。本レッスンでは、Javaプログラムにおいてデータベースを使う、データベース接続について扱っていきます。
JDBC
JDBC(Java Database Connectivity)は、Java言語でデータベースに接続するためのAPIです。JDBCは、Javaアプリケーションからデータベースにアクセスするための標準的なインターフェイスを提供します。簡単にいえば、Javaアプリケーションとデータベースの仲を取り持つ存在です。
JDBCは以下のふたつのパッケージによって成り立っています。
java.sql パッケージ: データベース接続の基本機能を提供
javax.sql パッケージ: 拡張機能を提供
本チャプターでは、基本機能を提供する java.sqlパッケージについて見ていきます。
java.sqlパッケージ
java.sqlパッケージは、Javaプログラミング言語でデータベースを操作するために使用されるクラスおよびインターフェイスが含まれています。
Connectionインターフェイス: データベースへの接続を管理
ResultSetインターフェイス: データベースから取得した結果を保持
DriverManagerクラス: JDBCドライバを管理
SQLExceptionクラス: データベースアクセス関連の例外
DataTruncationクラス: データのトリミングに関する例外
ResultSetMetaDataインターフェイス: 結果セットのメタデータを取得
DatabaseMetaDataインターフェイス: データベースのメタデータを取得
これらのクラスやインターフェイスを使用することで、Javaアプリケーションはデータベースに接続し、SQLを実行し、結果を取得することができます。他にも、データベースに関わる例外処理など、さまざまなデータベース関連の機能を利用することができます。
JDBCを使用してデータベースにアクセスするためには、まず「JDBCドライバ」を使用する必要があります。JDBCドライバについては後述しますが、JDBCがデータベースにアクセスする方法を定義しているのに対し、JDBCドライバは実際のデータベースへのアクセス、通信を担当しています。このJDBCドライバを読み込むにはDriverManagerクラスのregisterDriver()
メソッドを使用することで行うことができます。
次に、データベースへの接続を確立するために、DriverManagerクラスのgetConnection()
メソッドを使用します。このメソッドは、データベースのURL、ユーザー名、パスワードを指定することで、データベースへの接続を確立することができます。
確立した接続を使用して、SQLを実行するためには、StatementインターフェイスのcreateStatement()
メソッドまたはPreparedStatementインターフェイスのprepareStatement()
メソッドを使用します。これらのメソッドは、SQL文字列を指定することで、SQLを実行するためのオブジェクトを取得することができます。
SQLの実行結果は、ResultSetインターフェイスで取得することができます。ResultSetインターフェイスは、next()
メソッドを使用することで、次の行に移動し、各カラムの値を取得することができます。
具体的なコードについては、チャプター4で扱っていきます。
JDBCドライバマネージャーとJDBCドライバの関係
JDBCドライバは、Javaアプリケーションがデータベースにアクセスするためのインターフェイスを提供します。各データベースシステムには対応するAPIがあり、JDBCドライバはそれらのAPIを提供することで、Javaアプリケーションがデータベースへのアクセスを可能にします。Javaアプリケーションは、JDBCドライバマネージャーを使用して、対象のデータベースに対応したJDBCドライバを選択して、データベースに接続できます。例えば、MySQL、PostgreSQL、FileMakerなどがあるように、JDBCドライバは個々のデータベースにアクセスするために必要であり、JDBCドライバマネージャーは適切なJDBCドライバを選択するために使用されます。

Lesson 8
Chapter 2
DBの準備
本レッスンでは、MySQLというデータベースを使っていきます。MySQLは広く利用されているオープンソースのリレーショナルデータベース管理システム(RDBMS)です。構造化されたクエリ言語(SQL)を使ってデータを構造化して保存、整理、検索することができます。テキスト、数字、日付など多種多様なタイプのデータをサポートしています。
MySQLのダウンロード
まずは、MySQLをPCにインストールしていきましょう。まずは以下のリンクからMySQLインストーラーをダウンロードします。
https://dev.mysql.com/downloads/installer/
最新バージョンが表示されているので、mysql-installer-web-communityのダウンロードボタンを押下します。

以下のような画面に遷移しますが、サインアップの必要はないので、"No thanks, just start my download."を押下します。ダウンロードが始まるので、完了するまで待ちましょう。

MySQLのインストール
ダウンロードが完了したら、ファイルを実行します。
"Choosing a Setup Type" という画面が表示されるので、"Custom"を選択し、"Next > "ボタンを押下します。

"Select Products"画面に遷移するので、以下のようにインストールする内容を選択し、"Next > "ボタンを押下します。

"Download"画面に遷移するので"Execute"ボタンを押下します。

少し待機すると、ダウンロードが完了するので"Next > "ボタンを押下しましょう。

その後のインストール画面も同じように進めていき、以下の"Accounts and Roles"まで"Next > "を押下して進めましょう。

"Accounts and Roles"の画面に遷移したら、Rootアカウントのパスワードを設定します。ここで設定したパスワードは必ずメモしておいてください。パスワードの入力が終わったら、"Next > "ボタンを押下します。"Apply Configuration"という最終確認の画面に遷移するまで"Next > "ボタンを押下します。

"Execute"ボタンを押下します。完了を待ち、"Finish"ボタンを押下すると、MySQLのインストールは完了です。
DBの作成
MySQLのインストールが完了したので、早速MySQLでデータベースを作成していきましょう。様々な方法がありますが、今回はMySQL Shellを使っていきます。まずWindowsの検索窓からMySQL Shellを検索し、実行します。

まず初めに、MySQL Serverへの接続を行います。接続には、\connect
コマンドを使います。以下のようにコマンドを打ち込みましょう。パスワードが要求された場合は、先ほどインストール時に設定したパスワードを入力します。
MySQL Shell
\connect root@localhost:3306

MySQL Serverへ接続ができたら、サーバー上にDBを作成していきます。DBを操作するSQL言語に切り替えるため、以下のコマンドを打ち込みましょう。
MySQL Shell
\sql

SQLが使えるようになりました。まずは、DBを作成します。以下のSQL文を打ち込むことで、"mydb"(my databaseの略)という名前を持ったDBを作成できます。
MySQL Shell
CREATE DATABASE IF NOT EXISTS mydb;
次にUSE文を使って、作成した"mydb"に対して操作を行うことを伝えます。
MySQL Shell
USE mydb;
では、"mydb"の中にテーブルを作成していきましょう。以下のSQLを打ち込んで、顧客情報を管理するための"customers"テーブルを作ります。
MySQL Shell
CREATE TABLE customers (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
address VARCHAR(255),
email VARCHAR(100)
);

このレッスンでは、SQLの文法は詳しく扱いませんが、上記のSQL文を打ち込むことで、"id"、"name"、"address"、"email"という4つの列を持った"customers"テーブルが生成されます。「id」フィールドは自動的にインクリメントする主キーになっています。主キーとは、テーブル内で、行を一意に特定するための項目のことです。
テーブルを生成できたので、レコードを挿入してみましょう。レコードとは、テーブルの横の行のことを指します。また、テーブルの縦の列は、カラムと呼ばれます。以下のSQL文を用いて、"customers"テーブルにレコードを挿入していきます。
MySQL Shell
INSERT INTO customers (name, address, email)
VALUES ('John Doe', '123 Main Street', 'johndoe@example.com'),
('Jane Doe', '456 Oak Ave', 'janedoe@example.com'),
('Bob Smith', '789 Maple St', 'bobsmith@example.com');

このSQL文によって、"customers"テーブルに3つのレコードが挿入されました。実際に表示して確認してみましょう。レコードを表示するには、SELECT
文を使います。
MySQL Shell
SELECT * FROM customers;

このSQL文では"customers"テーブルからすべてのレコードを選択するように指示しています。表示されたテーブルを確認すれば、3つのレコードがテーブルに挿入されていることが確認できます。
本チャプターでは、MySQLをインストールし、SQLを用いて実際にデータベースを作成しました。次のチャプターでは、Eclipse側で、データベースとJavaを接続する準備を行っていきます。

Lesson 8
Chapter 3
接続情報の設定
前チャプターでは、インストールしたMySQLを使ってデータベースを実際に作成しました。本チャプターでは、Eclipseを使って、DB接続におけるJavaプログラム側の準備を行っていきます。
EclipseでJavaプロジェクトを作成
まずは、MySQLと接続するためのJavaプロジェクトを作成していきます。Eclipseを開いて、"ファイル(F)"→"新規(N)"→"その他(O)"を選択します。

ウィザードを選択という画面に遷移するので、"Javaプロジェクト"を選択して"完了(F)"を押下します。

プロジェクト名は、"MySqlSample"に設定し、"完了(F)"を押下します。

これで、Javaプロジェクトが作成できました。
MySQL用JDBCドライバの追加
プロジェクトを作成したので、次にMySQLに接続するためのJDBCドライバをプロジェクトに追加します。"MySqlSample"プロジェクトを右クリックし、"プロパティー(R)"を押下しましょう。

左側のリストから、"Javaのビルド・パス"を選択し、"ライブラリー(L)"タブからモジュールパスを選択して、右側にある"外部JARの追加"ボタンを押下します。

JARファイルを選択するウィンドウが開くので、MySQLと一緒にダウンロードした、Connector JのJARファイルを選択します。基本的には、"ローカルディスク(C:)/Program Files/MySQL/Connector J"の中に格納されています。

JARファイルの選択が完了したら、右下にある"適用して閉じる"ボタンを押下しましょう。

これで、MySQL用のJDBCドライバをプロジェクトに追加出来ました。
パッケージの作成
"MySqlSample"プロジェクト内にある"src"フォルダを右クリックし、"新規(N)"→"その他(O)"の順番で押下します。

ウィザード選択の画面に遷移するので、"パッケージ"と入力し、選択、"次へ(N)"を押下します。

パッケージ名を設定し、"完了(F)"ボタンを押下します。

クラスファイルの作成
作成した、パッケージの中にクラスファイルも作成しておきましょう。先ほど作成したパッケージを右クリックし、"新規(N)"→"その他(O)"の順番で押下します。

ウィザード選択画面では、"クラス"を選択し、"次へ(N)"を押下します。

クラス名を設定しましょう。今回は"ConnectMySQL"とします。"public static void main(String[] args)(V)"のチェックボックスにチェックを入れ、"完了(F)"を押下します。

DB接続情報の定数化
それでは、作成したクラスファイル内にプログラムを書いていきます。まずは、DB接続に必要な情報を利用しやすいように定数として定義していきましょう。プログラムは以下のようになります。
ConnectMySQL.java
package java_mysql;
public class ConnectMySQL {
private static final String MYSQL_DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String JDBC_CONNECTION = "jdbc:mysql://localhost:3306/mydb";
private static final String USER = "root";
private static String PASS = "*****";
public static void main(String[] args) {
}
}
定数PASS
に代入する文字列は、MySQLで設定したパスワードです。これで、DBに接続するための準備が整いました。次のチャプターでは、チャプター2でMySQL Shellを使って作成したDBから値を取り出していきます。

Lesson 8
Chapter 4
MySQLに接続してみる
前チャプターでは、Javaプロジェクトの作成から、MySQLに接続するための準備を行ってきました。本チャプターでは、チャプター2でMySQL Shellを使って作成したDBに接続し、値を取り出していきます。
接続処理の実装
前チャプターで作成したConnectMySQLクラスに、接続処理を実装していきましょう。
ソースコードは以下のようになります。
ConnectMySQL.java
package java_mysql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class ConnectMySQL {
//定数の準備
private static final String MYSQL_DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String JDBC_CONNECTION = "jdbc:mysql://localhost:3306/mydb";
private static final String USER = "root";
private static String PASS = "*****";
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//変数の準備
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
//①JDBCドライバのロード
Class.forName(MYSQL_DRIVER);
//②DB接続の確立
con = DriverManager.getConnection(JDBC_CONNECTION, USER, PASS);
//③SQLクエリの作成、実行
stmt = con.createStatement();
String SQL = "SELECT * FROM customers";
rs = stmt.executeQuery(SQL);
//④ResultSetオブジェクトから取得した情報を出力
while(rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
String address = rs.getString("address");
String email = rs.getString("email");
System.out.println(id + "|" + name + "|" + address + "|" + email);
}
}
}
まず、①のコメント箇所では、JDBCドライバのロードを行っています。②では、DBの情報、ユーザー名、パスワードを用いて、DB接続を確立させています。③の箇所では、SQL文"SELECT * FROM customers"を実行し、その結果をrs
に代入しています。④の箇所では、while文を使用してResultSetオブジェクトから取得した情報を標準出力で出力しています。
アプリケーションの実行
それでは、上記したプログラムを実行してみましょう。このプログラムで接続する"customers"テーブルは以下のようなものでした。

ConnectMySQLが選択されている状態で、"実行(R)"を押下します。
では、プログラム実行結果はどうでしょうか。

チャプター2で作成した"customers"テーブルの情報が出力されました。Javaプログラムを通じて、MySQLに接続し、SQL文をプログラム側から実行することができました。次のチャプターでは、DBの接続におけるリソースについて触れていきます。

Lesson 8
Chapter 5
接続の開始と終了
本チャプターでは、リソースの解放について学習します。DBに対して頻繁にSQL文を実行していく上でリソースの解放は重要です。まずは、前チャプターで用いたコードを見てみましょう。
ConnectMySQL.java
package java_mysql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class ConnectMySQL {
//定数の準備
private static final String MYSQL_DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String JDBC_CONNECTION = "jdbc:mysql://localhost:3306/mydb";
private static final String USER = "root";
private static String PASS = "*****";
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//変数の準備
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
//①JDBCドライバのロード
Class.forName(MYSQL_DRIVER);
//②DB接続の確立
con = DriverManager.getConnection(JDBC_CONNECTION, USER, PASS);
//③SQLクエリの作成、実行
stmt = con.createStatement();
String SQL = "SELECT * FROM customers";
rs = stmt.executeQuery(SQL);
//④ResultSetオブジェクトから取得した情報を出力
while(rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
String address = rs.getString("address");
String email = rs.getString("email");
System.out.println(id + "|" + name + "|" + address + "|" + email);
}
}
}
本チャプターでは、このコードを改良していきながら、リソースの解放について学んでいきます。現状のコードでは、例外処理がthrows句で行われているので、コンパイルエラーは発生しませんが、実行時エラーが発生した場合の処理を記述していません。まずは、try-catch文を用いて例外処理を行っていきます。
例外処理を適切に行うと以下のようになります。
ConnectMySQL.java
package java_mysql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class ConnectMySQL {
//定数の準備
private static final String MYSQL_DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String JDBC_CONNECTION = "jdbc:mysql://localhost:3306/mydb";
private static final String USER = "root";
private static String PASS = "*****";
public static void main(String[] args) {
//変数の準備
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try {
//①JDBCドライバのロード
Class.forName(MYSQL_DRIVER);
//②DB接続の確立
con = DriverManager.getConnection(JDBC_CONNECTION, USER, PASS);
//③SQLクエリの作成、実行
stmt = con.createStatement();
String SQL = "SELECT * FROM customers";
rs = stmt.executeQuery(SQL);
//④ResultSetオブジェクトから取得した情報を出力
while(rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
String address = rs.getString("address");
String email = rs.getString("email");
System.out.println(id + "|" + name + "|" + address + "|" + email);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
}
try-catch文を用いることで、適切な例外処理が実装できました。
リソースの解放
DB接続におけるリソースを正しく解放することは、アプリケーションのパフォーマンスに大きな影響を与えることがあります。リソースを解放とは、確保していたメモリを解放することです。これにより、アプリケーションがクラッシュしたり、接続のタイムアウトや、他のエラーが発生する可能性を回避することができます。
MySQLの接続リソースを正しく解放するにはResultSet、Statement、Connectionのリソースを順番に閉じる必要があります。これら3つはそれぞれclose()
メソッドを持っているので、それを呼び出すことで閉じることが出来ます。
リソースの解放を実装したコードが以下になります。
ConnectMySQL.java
package java_mysql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class ConnectMySQL {
//定数の準備
private static final String MYSQL_DRIVER = "com.mysql.cj.jdbc.Driver";
private static final String JDBC_CONNECTION = "jdbc:mysql://localhost:3306/mydb";
private static final String USER = "root";
private static String PASS = "*****";
public static void main(String[] args) {
//変数の準備
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try {
//①JDBCドライバのロード
Class.forName(MYSQL_DRIVER);
//②DB接続の確立
con = DriverManager.getConnection(JDBC_CONNECTION, USER, PASS);
//③SQLクエリの作成、実行
stmt = con.createStatement();
String SQL = "SELECT * FROM customers";
rs = stmt.executeQuery(SQL);
//④ResultSetオブジェクトから取得した情報を出力
while(rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
String address = rs.getString("address");
String email = rs.getString("email");
System.out.println(id + "|" + name + "|" + address + "|" + email);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
//⑤リソースの解放
try {
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (con != null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
⑤リソースの解放の箇所を見てください。リソースの解放は、DB接続が成功した場合も、エラーになった場合も行いたいので、try-catch-finally文を用います。finally句の中で、各リソースをclose()
メソッドで解放しています。これにより、例外が発生しても必ずリソースを解放することが保証されます。また、リソースを閉じるにあたり、SQLExceptionの例外処理が必要なので、さらにtry-catch文を用いて例外処理を行っています。
このように、ResultSet、Statement、およびConnectionオブジェクトを正しく解放することは、MySQLへのアクセスに伴い生じるリソースの使用量を最小限に抑えることができます。また、アプリケーションのパフォーマンスと安定性を向上させることができます。

Lesson 8
Chapter 6
プレースホルダの利用
本チャプターでは、プレースホルダという仕組みについて学んでいきます。プレースホルダは、SQL文に対して値を挿入する場所を可変なものとして確保することで、SQLインジェクションというセキュリティ攻撃のリスクを軽減するという効果があります。まずは、実際にコードを見ながらプレースホルダの仕組みを見ていきましょう。
プレースホルダの仕組み
プレースホルダでは、SQL文の固定部分と可変部分を分けます。まずは通常のSQL文を見てみましょう。
SQL
INSERT INTO customers (name, address, email) VALUES ("John Doe", "123 Main St", "john.doe@example.com");
このSQL文では、customersテーブルに対して、新しいレコードを挿入しようとしています。この例では、SQL文の中に"John Doe"などの値が直接書き込まれていますが、ユーザーが入力したデータをレコードに挿入する会員登録機能を想定すると、現状"John Doe", "123 Main St", "john.doe@example.com"となっている部分は可変でなければなりません。では、以下にプレースホルダを使用したコードをお見せします。
SQL
String sql = "INSERT INTO customers (name, address, email) VALUES (?, ?, ?)";
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setString(1, name);
pstmt.setString(2, address);
pstmt.setString(3, email);
pstmt.executeUpdate();
sqlに代入されているSQL文に注目してください、挿入する値の部分が全て"?"で置き換えられています。setStringメソッドを使って、"?"の部分に対応する値を設定しています。これにより実際に値を含んだSQL文が生成されます。以上がプレースホルダの仕組みです。※name、address、emailには、ユーザーが入力した値が代入されているとします。
SQLインジェクション
プレースホルダを使用することで、SQLインジェクションというセキュリティ攻撃を防ぐことができます。では、SQLインジェクションとは、具体的にどういった攻撃なのでしょうか。
SQLインジェクションとは、Webアプリケーションにおいて、攻撃者が入力フィールドに不正なSQL文を挿入することによって、Webアプリケーション上で動作するデータベースを攻撃するセキュリティ攻撃のことです。
例えば、次のようなWebアプリケーションがあったとします。
Sample
String username = request.getParameter("username");
String password = request.getParameter("password");
String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
このようなWebアプリケーションを攻撃する場合、攻撃者は入力フィールドに以下のような文字列を入力することで、データベース上のテーブルやデータを不正に操作することができます。
username: ' OR '1'='1
password: anything
このような入力によって、実際に実行されるSQL文は次のようになります。
SQL
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = 'anything'
このSQL文は、常に真となる条件を指定しているため、データベース上の全てのユーザー情報を取得できてしまいます。このように不正なSQL文を入力することで、データベースを攻撃することをSQLインジェクションといいます。
PreparedStatement
SQLインジェクションについて理解したところで、もう一度プレースホルダを実装したコードを見てみましょう。
SQL
String sql = "INSERT INTO customers (name, address, email) VALUES (?, ?, ?)";
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setString(1, name);
pstmt.setString(2, address);
pstmt.setString(3, email);
pstmt.executeUpdate();
PreparedStatement
オブジェクトが使われているのが分かります。PreparedStatementでは、SQL文と後から挿入する値が別々に管理され、SQL文として解釈されません。この特徴が、SQLインジェクションを防ぐ理由になっています。
ここまで本レッスンでは、DB接続について学んできました。実際にMySQLとのJavaプログラムの接続を行い、JavaにおけるDB接続が以下に実現されているか理解できたと思います。次レッスンでは、MVCモデルという設計モデルを学びながら簡単なWebアプリケーションを開発していきます。
