Ch11. JDBC
JDBCのクラス
Connection con = null; Statement stmt = null; ResultSet rs = null; String url = "jdbc:mysql://localhost/golddb"; con = DriverManager.getConnection(url,"root", "*****"); stmt = con.createStatement(); String sql = "SELECT dept_code, dept_name FROM department"; rs = stmt.executeQuery(sql); while (rs.next()) { System.out.println("dept_code : " + rs.getInt(1)); System.out.println("dept_name : " + rs.getString("dept_name")); }
JDBCでのDBコネクションでは3つのクラスが登場する。
クラス | 取得方法 | 説明 |
---|---|---|
Connection | DriverManager.getConnection | DBとのコネクションを補完する |
Statement | connectionObj.createStatement() | statementObj.executeQuery("SQL") で利用する |
ResultSet | statementObj.executeQuery("SQL") で取得 | next()でレコードを選択、getString(1), getInt(カラム名)でカラム選択 |
カラムごとの取得方法
取得するデータ型ごとに異なるメソッドを利用する。
また、ResultSetで取得できる日付・時刻データ型はjava.time
のそれと異なるため、クラスキャストが必要になる。
java.sql.Date sqlDate = rs.getDate(1); java.time.LocalDate localDate= sqlDate.toLocalDate(); System.out.println("localDate : " + localDate + " sqlDate : " + sqlDate); java.sql.Time sqlTime = rs.getTime(2); java.time.LocalTime localTime= sqlTime.toLocalTime(); System.out.println("localTime : " + localTime + " sqlTime : " + sqlTime); //localDate : 2020-11-12 sqlDate : 2020-11-12 //localTime : 12:05:01 sqlTime : 12:05:01
通常のデータだけでなく、SQLのエラーコード等も取得できる。
catch (SQLException e) { System.out.println(e.getErrorCode());//'1146' System.out.println(e.getSQLState());//'42S02' }
executeQuery / executeUpdate
executeQuery
で取得した値はresultSet
というオブジェクトで返却される。executeQueryの結果が0件だったとしても空っぽのresultSet
が返却されるのでnullが返却されることは無い(Optionalみたいな仕組み)。
String sql = "SELECT field1, field2, filed3 FROM mytableA WHERE field1 = 100"; rs = stmt.executeQuery(sql); System.out.println(rs == null); //false
レコードの挿入処理・削除処理であってもexecuteUpdate
を利用する。
executeUpdateの戻り値は「データベースへの変更が発生したかどうか」が【訂正】変更が発生した行数が返却される。0
または1
のint型で返却される。
String sql = "UPDATE department set " + "dept_address='Tokyo', pilot_number='03-6666-xxxx' "+ "where dept_code = 2" ; String sql2 = "UPDATE department set " + "dept_address='Melbourne', pilot_number='03-6666-xxxx' "+ "where dept_code = 1" ; try(Connection con = DbConnector.getConnect(); Statement stmt = con.createStatement() ) { int col = stmt.executeUpdate(sql); int col2 = stmt.executeUpdate(sql2); System.out.println("更新対象無し : " + col + "更新対象アリ : " + col2); //'更新対象無し : 0更新対象アリ : 1'
一方、例えば主キー制約で更新に失敗したりした場合は、executeUpdate
は返却されず、例外となる。
String sql = "INSERT INTO department VALUES " + "(6,'Finance','Sydney', '112233')"; try(Connection con = DbConnector.getConnect(); Statement stmt = con.createStatement()) { int col = stmt.executeUpdate(sql); System.out.println("col : " + col); } catch (SQLException e) { System.out.println(e.getMessage()); //'Duplicate entry '6' for key 'department.PRIMARY'' }
execute
executeStatement
は戻り値としてResultSet
が、executeupdate
は戻り値としてintが返却されていた。
updateやselect両方で利用できるexecute
クラスは戻り値にboolean
を返す。
String sql2 = "UPDATE department set " + "dept_address='Sydney', pilot_number='03-6456-xxxx' "+ "where dept_code = 1" ; try(Connection con = DbConnector.getConnect(); Statement stmt = con.createStatement() ) { boolean col = stmt.execute(sql2); ResultSet result = stmt.getResultSet(); System.out.println(result); System.out.println( "更新対象アリ : " + col); //更新対象アリ : false' }
execute
がtrue
を返却するのはResultSet
に値が挿入されたときだけ。
たとえば、更新に成功してもResultSetに値は入らないのでfalse
が返却される。
逆にSELECT文で値一件も取得できなくとも、ResultSet
には空のオブジェクトが挿入されるため、true
となる。
String sql2 = "SELECT * FROM golddb.department WHERE dept_code = 3" ; try(Connection con = DbConnector.getConnect(); Statement stmt = con.createStatement() ) { boolean col = stmt.execute(sql2); ResultSet result = stmt.getResultSet(); System.out.println(result); while(result.next()) { result.getString("dept_name"); } System.out.println( "更新対象アリ : " + col); //更新対象アリ : false' } catch (SQLException e) { System.out.println(e.getMessage()); }
ResultSetの拡張
ここまではResultSet
のメソッドに対してnext
しか利用していなかったが、他にも様々なメソッドを利用できる。
ただし、ResultSet間のカーソルを扱えるのはTYPE_SCROLL_INSENSETIVE
をサポートしている場合のみで、ドライバの種類によっては利用できない。
クラス | 取得方法 | 説明 |
---|---|---|
previous | nextの反対 | |
beforeFirst() | 取得行の最初の行の前に移動 | |
afterLast() | 取得行の最後の行の後ろに移動 | |
absolute(int x) | 1で最初の行、-1で最後の行に移動できる |
ResultSetで得られた結果を通して、そのままレコードの更新を実施することが出来る。 レコードの挿入も行えるが、それには専用の(Insert)行まで移動する必要がある。
String sql2 = "SELECT * FROM golddb.department" ; try( Connection con = DbConnector.getConnect(); Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE) ) { boolean col = stmt.execute(sql2); ResultSet result = stmt.getResultSet(); System.out.println(result); while(result.next()) { result.getString("dept_name"); } result.absolute(-1); result.updateString(2, "HR"); result.updateRow();//Commit; result.moveToInsertRow(); result.updateInt(1,4); result.updateString(2, "Reserch"); result.updateString(3, "Yokohama"); result.updateString(4, "03-6666-XXXX"); result.insertRow();//Commit result.beforeFirst(); while(result.next()) { result.getString("dept_name"); } System.out.println( "更新対象アリ : " + col); //更新対象アリ : true' } catch (SQLException e) { System.out.println(e.getMessage()); }
ResultSetは一度更新がかかってしまうと、閉じられてしまいnext
で開くことが出来なくなっていまう。