JavaGoldの資格取得のためにアウトプットかつ、備忘録のための記事です。
誤り等、わかりずらい等があればご指摘お願いいたします
JDBCを使用したデータベース接続
内容
・JDBCを使用したデータベース接続
・SQLステートメントの実行
・ResultSetの拡張
JDBCとは
JDBCとは、Javaプログラムからデータベースにアクセスするための共通インタフェース。
使用するパッケージは以下
・java.sql
:データベースに格納されたデータへアクセスして処理する基本APIを提供。
・javax.sql
:データベースにアクセスする際、サーバー側での処理(接続プールや分散トランザクション等)を行う場合に使用するAPI
データベースにアクセスするクラスは、共通インタフェースとして提供されているJDBC APIを使用することで、接続するデータベース製品の違いを意識することなく実装できる。
JDBCドライバ
JDBCドライバはJavaプログラムとデータベースを紐づけるために必要なJDBCインタフェースを実装したクラス。
基本的なJDBCアプリケーションの作成
JDBCを使用するときの一般的な流れ
1:java.sqlパッケージのインポート
↓
2:データベースの指定
↓
3:データベースとの接続
↓
4:ステートメントの取得
↓
5:SQL文の実行
↓
6:結果の取得と処理
↓
7:接続のクローズ
また、java.sqlパッケージで提供されている主なクラス、インタフェースは以下↓
・DriverManagerクラス
:データベースのドライバを管理し、データベースとの接続を支援する。
・Connectionインタフェース
:特定のデータベースとの接続(セクショ)を表現する。
・Statementインタフェース
:静的SQL文を実行し、作成された結果を返すために使用さるオブジェクト。
・ResultSetインタフェース
:データベースの結果セットを表すデータオブジェクト。
Connection con = null;
Statement stmt = null;
ResultSet rst = null;
try {
// 2:データベース指定
// 指摘修正
//String url = "jdbc:mysql//○○";
String url = "jdbc:mysql://<hosts>/<database>";
// 3:データベースとの接続
con = DriverManager.getConnection(url, "root", "training");
// 4:ステートメントの取得
stmt = con.createStatement();
// 5:SQL文の実行
String sql = "select * from department";
rst = stmt.executeQuery(sql);
// 6:結果の取得と処理
while(rst.next()) {
System.out.println("dept_code : " + rst.getInt(1));
System.out.println("dept_name : " + rst.getString(2));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 7:接続のクローズ
try {
if (rst != null) rst.close();
if(stmt != null) stmt.close();
if (con != null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
解説
2:データベース指定
通信先のデータベースを特定するためのJDBC URLをも実で準備している。
URLの構文は以下の通り。
プロトコル、サブプロトコル、サブネーム名を含み、:で区切る
jdbc:<subprotocol>:<subname>
3:データベースとの接続
データベース接続をするにはDriverManagerクラス
のgetConnection()メソッド
を呼び出し、Connectionオブジェクトを取得する。
以下がDriverManagerクラスの主な接続用メソッド
static Connection getConnection(String url) throws SQLException
┗指定されたデータベースのURLへの接続を試みる
static Connection getConnection(String url, String user, String password) throws SQLException
┗指定されたデータベースのURLへ、ユーザー名・パスワードを使用して接続を試みる
ConnectionObjectを取得できなかった場合は、SQLException例外がスローされる
4:ステートメントの取得
標準的な問い合わせを実行するには、Statementオブジェクトを使用する。
StatementオブジェクトによりSQLコマンドを実行する。Statemntオブジェクトは、Connectionインタフェースの`createStatement()メソッド'で取得する。
5:SQL文の実行
SQL文を文字列でまず用意する。
Statementインタフェースのメソッドを使用してSQL文を実行する。
今回はSELECT文なので、executeQuery
を使用する。
6:結果の取得と処理
executeQueryの実行によって、ResultSetオブジェクトとして検索結果が返される。
ResultSetオブジェクトは、問い合わせにより返されたデータを表し、1行ずつ処理ができる。
ResultSetオブジェクトから値を取り出すには以下のように列・行にアクセスする。
・行へのアクセス
next()
メソッドにより、1行ずつデータを取り込む。
next()メソッド
は、1行ずつデータにアクセスし、次の行があればtrueを返す
ResultSetオブジェクト生成時は、カーソルが先頭行の前にあるため、必ず一回はnext()メソッドを実行しないと行を取り出すことはできない。
next()を一回も呼び出さずにデータの取り出しを試みるとSQLExceptionが発生する
・列へのアクセス
getterメソッドで引数に列番号を指定することによりデータを取り出せる。
列番号はResultSetオブジェクト内の左から右へ順に降られた番号で、最初の列は1。
また、列名を指定して取り出すこともできる。
getterメソッドでは、getXXX(列名) もしくはgetXXX(列番号) というメソッド名が定義されており、XXXの部分にはJavaのデータ型名が入る。
7:接続のクローズ
すべての処理が終了したらリソースの解放をす。
Connectionインタフェース、Statementインタフェース、ResultSetインタフェースは使用したリソースを解放するためにclose()メソッド
を提供している。
例外
Javaアプリケーションがデータベースと通信した時に発生するエラーはデータベースからアプリケーションへ通知される。エラーの通知にはSQLException
オブジェクトが使用される。
発生する理由は様々。
例↓
・ネットワークケーブルが物理的な問題により通信が切断した。
・SQLコマンドのフォーマットが不適切である。
・サポートされていない機能を使用。
・存在しない列を参照した。
SQLExceptionクラスのメソッドを使用して、エラーメッセージを取得することができる。
主なクラス↓
int getErrorCode()
ベンダ固有の例外コードを取得する。
String getSQLState()
SQLStateを取得する。
SQLステートメントの実行
JDBCでは3種類のステートメントを使用できる。
インタフェースとして提供される。
Statement
:標準的なSQL文を実行
PreparedStatement
:プリコンパイルされたSQL文を実行
CallableStatement
:ストアドプロシージャを実行
Statementインタフェース
標準的な問い合わせを実行するには、ConnectionインタフェースのcreateStatementメソッドからStatementオブジェクトを取得する。
Statementインタフェースの主なメソッド
ResultSet executeQuery(String sql) throws SQLException
単一のResultSetオブジェクトを返す指定されたSQL文を実行する。
該当するレコードがない場合でもnullにはならない。
int executeUpdate(String sql) throws SQLException
指定されたSQL文を実行する。SQL文はデータ操作言語文(INSERT,UPDATE,DELETE)、あるいは、DDL文のような何も返さないSQL文を指定する。
戻り値は、引数がDML文の場合は、行数を返す。何も返さないSQL文の場合は0を返す。
boolean execute(String sql) throws SQLException
SQL文の実行結果がResultSetオブジェクトの場合はtrueを、更新行数または結果がない場合はfalseを返す
SELECT - executeQuery()メソッドで問い合わせ
String sql = "select * from department where dept_code = " + args[0];
try(Connection con = DBConection.connection();
Statement st = con.createStatement();
ResultSet rst = st.executeQuery(sql)) {
if(rst != null) System.out.println("rs != null");
while(rst.next()) {
System.out.println("dept_name : " + rst.getString("dept_name"));
}
} catch (Exception e) {
e.printStackTrace();
}
INSERT - executeUpdateメソッドで問い合わせ
String sql = "INSERT INTO department values " + "(6,'planning', 'Yokohama', '000-0000-0000')";
try(Connection con = DBConection.connection();
Statement st = con.createStatement();) {
// 指摘修正
// int col = st.executeUpdate(sql);
int row = st.executeUpdate(sql);
System.out.println("col : " + col);
} catch (Exception e) {
e.printStackTrace();
}
UPDATE - executeUpdateメソッドで問い合わせ
String sql = "update department set dept_address = 'Tokyo' where dpt_code = " + args[0];
try(Connection con = DBConection.connection();
Statement st = con.createStatement();) {
int col = st.executeUpdate(sql);
System.out.println("col : " + col);
} catch (Exception e) {
e.printStackTrace();
}
更新できた件数を返す。
DELETE - executeUpdate()メソッドで問い合わせ
String sql = "delete from department where dpt_code = " + args[0];
try(Connection con = DBConection.connection();
Statement st = con.createStatement();) {
int col = st.executeUpdate(sql);
System.out.println("col : " + col);
} catch (Exception e) {
e.printStackTrace();
}
execute()メソッドでSQL文の実行
一般的には検索処理文の実行にはexecuteQuery(),更新処理文の実行にはexecuteUpdate文を使用するが、どっちの処理でも実行可能なメソッドとしてexecute() が提供されている。
引数には、検索/更新いずれの処理文が指定可能。
処理内容によって戻り値が違うので、戻り値の型はboolean型になっている。
ResutlSetオブジェクトが返ってきている場合は、true
更新行もしくは結果がない場合は、falseが返却される。
以下は結果を取り出すStatementインタフェースのメソッド↓
ResultSet getResutlSet() throw SQLException
┗ ResultSetオブジェクトを取得する
int getUpdateCount throws SQLException
┗ 更新行数を取得する。
String[] sqls = {
"insert into department values (7, 'planing', 'Yokohama', '000-0000-0000')",
"select dept_name from department where dept_code = 2"
};
try(Connection con = DBConection.connection();
Statement st = con.createStatement();) {
for(String sql : sqls) {
boolean isResultSet = st.execute(sql);
if (isResultSet) {
ResultSet rs = st.getResultSet();
rs.next();
System.out.println(rs.getString(1));
}else {
int count = st.getUpdateCount();
System.out.println(count);
}
}
} catch (Exception e) {
e.printStackTrace();
}
executeXXXメソッドの特徴
以下の通り↓
execute(String sql)
戻り値:boolean
ture :ResultSetオブジェクトの取得が可能
false:更新行の取得が可能 or 結果がない
executeQuery(String sql)
戻り値:ResultSet
結果の取得には一回はnext()を呼ばないといけない。
該当コードがない場合でも、ResultSetはnullにはならない
executeUpdate(String sql)
戻り値:int
更新行が返る。
更新した行がなかった場合は0が返る。
ResultSetの拡張
ResultSetオブジェクトの高度な機能
ResultSetオブジェクトでは以下のような機能を使用できる。
・問い合わせ結果のスクロール、絶対/相対位置特定
・ResultSetオブジェクト上でデータの挿入・更新
スクロール機能や更新処理が可能なResultSetオブジェクトを取得するには、各ステートメントの取得時に、ResultSetインタフェースで提供されている定数を指定する。
以下がResultSetインタフェースで定義されている定数
CONCUR_READ_ONLY
:更新できないResultSetオブジェクトの並行処理モードを示す
CONCUR_UPDATABLE
:更新できるResultSetオブジェクトの並行処理モードを示す
TYPE_FORWARD_ONLY
:カーソルが順方向にしか移動しないResultSetオブジェクトを示す
TYPE_SCROLL_INSENSITIVE
:スクロール可能だが、データベースのデータに対して行われた変更を反映しないResultSetオブジェクトのタイプを示す
TYPE_SCROLL_SENSITVE
:スクロール可能でデータベースの最新の内容を反映するResultSetオブジェクトのタイプを示す
問い合わせ結果のスクロール、絶対/相対位置指定
Statementオブジェクトを使用して、スクロール可能なResultSetオブジェクトを取得する
次のコード例はStatementオブジェクトを取得する際に、ResultSetインタフェースの定数を指定している
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
createStatement()メソッドの第一引数に、TYPE_SCROLL_INSENSITIVEもしくはTYPE_SCROLL_SENSITVEを指定することで、ResultSetオブジェクト内を順方向or逆方向に移動できる。
第二引数には、CONCUR_UPDATABLEを指定することで取得したResultSetオブジェクトを通じてレコードの挿入や更新、削除を行うことができる。
スクロール可能なResultSetオブジェクトでは、next()メソッド以外にもカーソルを任意に移動するメソッドを使用できる。
以下、ResultSetインタフェースのカーソル移動用メソッド↓
boolean absolute(int row) throws SQLException
┗ カーソルをこのResultSetオブジェクト内の指定された行番号に移動する。
boolean relative(int row) throws SQLException
┗ カーソルを正または、負の相対行数だけ移動する
boolean next() throws SQLException
┗ カーソルを現在位置から1行順方向に移動する
boolean previous() throws SQLException
┗カーソルをこのResultSetオブジェクト内の前の行に移動する
boolean first() throws SQLException
┗ カーソルをこのResultSetオブジェクト内の先頭の行に移動する
boolean last() throws SQLException
┗ カーソルをこのResultSetオブジェクト内の最終行に移動する
void afterLast() throws SQLException
┗ カーソルをこのResultSetオブジェクト内の最終行の直前に移動する
void beforeFirst() throws SQLException
┗ カーソルをこのResultSetオブジェクト内の先頭行の直前に移動する
int getRow() throws SQLException
┗ 現在の行番号を取得する。最初の一行は1となる
指摘修正
1:2024-04-18