Javaアプリケーション 開 発 ガイド 一 般 編 第 2 版 2011 年 9 月 富 士 通 株 式 会 社
まえがき 本 書 の 目 的 本 書 は JavaアプリケーションからSymfoware Serverを 利 用 する 方 法 について 説 明 しています 以 下 の 内 容 が 理 解 できることを 目 標 としています JDBCを 用 いてJavaアプリケーションからSymfoware Serverに 接 続 する 方 法 (データソースを 用 いてSymfoware Serverに 接 続 する 方 法 ) JavaアプリケーションからSymfoware Serverにアクセスして SQLを 実 行 する 方 法 (PreparedStatementを 用 いてSQLを 実 行 する 方 法 とResultSetの 様 々な 使 用 方 法 ) 本 書 の 読 者 本 書 は Symfoware ServerにアクセスするJavaアプリケーションを 開 発 される 方 に 読 んでいただくよう に 書 かれています 本 書 を 読 むには 以 下 の 知 識 が 必 要 です Symfoware Serverに 関 する 知 識 SQLに 関 する 知 識 Javaに 関 する 一 般 知 識 JDBCに 関 する 一 般 知 識 Javaアプリケーション 開 発 ガイド 入 門 編 の 内 容 を 理 解 できることを 前 提 としています i
目 次 第 1 章 JDBCドライバの 種 類 と 選 択... 1 1.1 JDBCドライバがサポートするAPI... 2 1.2 どのJDBCドライバを 使 用 すればよいか... 3 1.3 JDBCの 規 格 のバージョン... 4 第 2 章 データソースを 用 いた 接 続... 5 2.1 Connectionオブジェクトを 作 成 する2つの 方 法... 6 2.2 データソース... 7 2.3 ネーミングサービス... 8 2.4 Symfoware Serverのデータソース 登 録 ツール... 10 2.5 DataSourceを 使 用 して 接 続 する 方 法... 12 2.6 Connection Managerを 使 用 する 場 合 の 接 続 先... 15 第 3 章 SQL 文 の 準 備... 16 3.1 SQL 文 を 表 すオブジェクト... 17 3.2 PreparedStatementクラスを 使 用 する 利 点... 18 3.3 SQL 文 の 中 でパラメーターを 使 う... 19 3.4 同 じSQL 文 を 何 度 も 使 う... 21 第 4 章 データベースの 検 索... 23 4.1 検 索 の 実 行... 24 第 5 章 検 索 結 果 の 取 り 出 し... 27 5.1 ResultSetの 基 本 操 作... 28 5.2 カーソルを 移 動 させる 方 法... 29 5.3 カーソルを 自 由 に 動 かす 方 法... 30 5.4 カーソルを 動 かすためのメソッド... 32 5.5 ResultSetの 保 持 機 能... 33 5.6 ResultSetの 保 持 機 能 を 使 う 上 での 注 意... 36 第 6 章 データの 更 新... 39 6.1 更 新 可 能 なResultSetオブジェクトの 作 成... 40 6.2 ResultSetオブジェクトを 用 いたデータの 更 新... 42 6.3 カーソルを 使 用 した 更 新... 47 6.4 RowIDを 使 用 したデータ 更 新... 49 6.5 RowIDを 使 用 したデータ 更 新 の 注 意 点... 52 6.6 バッチ 更 新... 54 ii
6.7 異 なるSQL 文 を 一 括 実 行... 56 6.8 同 一 のSQL 文 をパラメーターを 変 えて 一 括 実 行... 58 第 7 章 例 外 処 理 と 後 始 末... 60 7.1 例 外 処 理... 61 7.2 オブジェクトのクローズ... 63 iii
第 1 章 JDBCドライバの 種 類 と 選 択 1
1.1 JDBCドライバがサポートするAPI JDBC を 用 いてデータベースを 利 用 する 手 順 は どのデータベースソフトを 使 用 している 場 合 でも 同 じです ただし JDBC の 規 格 のうち どの API をサポートしているかは データ ベースソフトによって 異 なります また データベースソフトによっては 独 自 に JDBC の 仕 様 を 拡 張 し そのデータベースソフト 固 有 の 機 能 を 追 加 している 場 合 もあります Symfoware Server の JDBC ドライバがサポートしている API の 一 覧 が マニュアル アプリ ケーション 開 発 ガイド(JDBC 編 ) に 掲 載 されています また Java API リファレンス が 製 品 に 付 属 しています クラスやメソッドの 詳 細 は Java API リファレンス に 記 載 されています これらを 参 照 して アプリケーションを 作 成 してください なお Symfoware Server では Java のアプリケーションで 埋 込 み SQL を 使 用 することはでき ません Java のアプリケーションから Symfoware Server を 利 用 する 場 合 は JDBC を 用 い てください 2
1.2 どのJDBCドライバを 使 用 すればよいか JDBC のドライバには タイプ 1 からタイプ 4 までの 4 つのタイプがあります このうち Symfoware Server はタイプ 2 のドライバをサポートしています タイプ 2 は JDBC ドライバが Symfoware Server のクライアントライブラリを 利 用 してデー タベースにアクセスするタイプです [ 補 足 ] Symfoware Server V9 以 前 のバージョンで RDA-SV を 使 用 する 場 合 Symfoware Server V9 以 前 のバージョンでは クライアントとデータベースサーバとの 通 信 に RDA-SV というソフトウェアを 使 用 する 方 式 がサポートされていました RDA-SV 連 携 を 使 用 する 場 合 には タイプ 4 の JDBC ドライバを 使 用 する 必 要 がありました Symfoware Server V9 以 前 は JDBC のタイプを 以 下 のように 使 い 分 けます タイプ 2 ローカルアクセスまたは RDB2_TCP 連 携 で Symfoware Server に 接 続 する 場 合 に 使 用 されます タイプ 4 RDA-SV 連 携 で Symfoware Server に 接 続 する 場 合 に 使 用 されます 実 際 には どちらのタイプのドライバを 使 用 するかを 選 択 するのではなく 接 続 形 態 を 選 択 します 接 続 形 態 を 選 択 すると それに 応 じたドライバのタイプが 使 用 されます 接 続 形 態 を 選 択 するには 以 下 のようにします Symfoware Server に 添 付 されているデータソース 登 録 ツールの 画 面 に 表 示 されている 中 から 選 択 する DriverManager の getconnection メソッドに 指 定 する URL で 指 定 する 3
1.3 JDBCの 規 格 のバージョン JDBC のドライバのタイプとは 別 に JDBC 自 体 の 規 約 のバージョンがあります Symfoware Server V9 までは JDBC2.X に 対 応 しています Symfoware Server V10 以 降 は JDBC3.X と JDBC4.X にも 対 応 しています そのため V10 以 降 では JDBC ドライバとして 以 下 の 3 種 類 が 提 供 されています fjsymjdbc2.jar:jdbc2.x 対 応 ドライバモジュール fjsymjdbc3.jar:jdbc3.x 対 応 ドライバモジュール fjsymjdbc4.jar:jdbc4.x 対 応 ドライバモジュール Symfoware Server V10 では 使 用 するドライバモジュールを 選 択 して そのパスを CLASSPATH に 設 定 してください 通 常 は 最 も 新 しい 規 格 である JDBC4.X に 対 応 したモジュールを 使 用 します Symfoware Server V9 までは JDBC2.X 対 応 のドライバモジュールのみです 使 用 する JDBC のバージョンによって JDK のバージョンも 考 慮 する 必 要 があります 新 し い 規 約 の JDBC を 使 用 するには 新 しいバージョンの JDK が 必 要 です 詳 細 は マニュアル アプリケーション 開 発 ガイド(JDBC ドライバ 編 ) を 参 照 してください 4
第 2 章 データソースを 用 いた 接 続 5
2.1 Connectionオブジェクトを 作 成 する2つの 方 法 Java プログラムから Symfoware Server を 利 用 するためには まずデータベースに 接 続 する 必 要 があります データベースに 接 続 するには JDBC の Connection オブジェクトを 作 成 し ます Connection オブジェクトを 作 成 する 方 法 には 以 下 の 2 つがあります DriverManager を 使 用 する 方 法 DataSource を 使 用 する 方 法 DriverManager を 使 用 する 方 法 は 入 門 編 で 説 明 しました ここでは DataSource を 使 用 す る 方 法 について 説 明 します 6
2.2 データソース データソースとは データを 格 納 する 機 構 を 一 般 的 に 表 したものです ここではもちろん Symfoware Server のデータベースを 表 します DataSource オブジェクトはデータソースを 表 すオブジェクトです Java アプリケーション の 中 では DataSource オブジェクトは データベースへの 接 続 を 表 す Connection オブジェ クトを 作 成 するために 使 用 します DataSource オブジェクトを 用 いる 方 法 には 以 下 の 利 点 があります JDBC ドライバに 関 する 情 報 をアプリケーションの 中 で 指 定 する 必 要 がなくなります どのドライバを 用 いてどのデータベースに 誰 がアクセスするのか といった 情 報 は データソース 情 報 としてアプリケーションの 外 部 で 管 理 されます アプリケーション 内 では 外 部 で 管 理 されている 情 報 のキーとなるデータソース 名 を 指 定 するだけです これによって 接 続 先 の 変 更 などに 柔 軟 に 対 応 することができるようになります コネクションプールを 使 うことができるようになります データベースへの 接 続 と 切 断 は 比 較 的 コストの 高 い 処 理 です 接 続 をキャッシュして おくことで アプリケーションの 性 能 向 上 が 期 待 できます アプリケーションからはデータソース 名 を 指 定 して DataSource オブジェクトを 作 成 します その DataSource オブジェクトを 用 いて Connection オブジェクトを 作 成 します Connection オブジェクトを 作 成 することによって データベースに 接 続 します 7
2.3 ネーミングサービス データソースに 関 する 情 報 は アプリケーションとは 別 個 に 管 理 します そのためにネー ミングサービスを 使 用 します ネーミングサービスは Java アプリケーションともデータ ベースとも 別 に 動 作 しているプログラムで オブジェクトと 名 前 の 対 応 を 管 理 する 役 目 を 持 っています データソースの 情 報 は ネーミングサービスに 予 め 登 録 しておきます Java には アプリ ケーションがネーミングサービスを 利 用 するための API が 用 意 されています ネーミング サービスを 利 用 するための API を JNDI と 呼 びます Java アプリケーションは データソー ス 名 をキーにして JNDI の API を 用 いることで ネーミングサービスに 登 録 されているデー タソースを 利 用 できます 1 登 録 ネーミンサービス データソース 情 報 データソース 情 報 Javaアプリケーション データベース データソース 名 2 検 索 DataSource オブジェクト 3オブジェクト 生 成 4getConnectionで 接 続 8
ネーミングサービスとしては AP サーバである Interstage が 提 供 している 機 能 を 使 用 でき ます ネーミングサービスへのデータソースの 登 録 も Interstage の 機 能 である 管 理 コン ソールから 行 うことができます 詳 細 は Interstage のマニュアルを 参 照 してください Symfoware Server には 専 用 のネーミングサービスとデータソース 登 録 ツールが 付 属 してい ます Interstage を 利 用 する 場 合 は Interstage のネーミングサービスを 使 用 することを 推 奨 します 9
2.4 Symfoware Serverのデータソース 登 録 ツール Symfoware Server には Symfoware Server 専 用 のデータソース 登 録 ツールとネーミングサ ービスが 付 属 しています データソース 登 録 ツールを 利 用 することで GUI 画 面 上 でデータソースの 情 報 を 登 録 するこ とができます 下 記 の 画 面 は Symfoware Server に 付 属 しているデータソース 登 録 ツールの 画 面 です こ の 画 面 上 でデータソースの 情 報 を 設 定 します 登 録 した 情 報 は Symfoware Server に 付 属 しているネーミングサービスによって 管 理 されま す このネーミングサービスには Java アプリケーションから JNDI を 用 いてアクセスでき ます 10
詳 細 な 手 順 は マニュアル アプリケーション 開 発 ガイド(JDBC 編 ) を 参 照 してください 11
2.5 DataSourceを 使 用 して 接 続 する 方 法 いったんデータソースを 登 録 できたなら Java アプリケーション 内 からネーミングサービ スにアクセスすることによって 登 録 しておいたデータソースを 利 用 することができます データソースは DataSource オブジェクトとして 表 されます DataSource オブジェクトの getconnection メソッドを 呼 び 出 すことで Connection オブジェクトを 作 成 することがで きます Connection オブジェクトが 作 成 できたら DriverManager を 用 いて 作 成 した Connection オ ブジェクトの 場 合 と 同 様 に Symfoware Server に 処 理 を 依 頼 することができます Interstage を 利 用 する 場 合 Interstage のネーミングサービスを 利 用 する 場 合 は あらかじめ Interstage の 管 理 コンソ ールからデータソースを 登 録 しておく 必 要 があります 登 録 されているデータソースを Java アプリケーションから 利 用 するには 以 下 のようにします ( 例 ) // ネーミングサービスの InitialContext を 作 成 する Hashtable env = new Hashtable(); env.put(context.initial_context_factory, "com.fujitsu.interstage.j2ee.jndi.initialcontextfactoryforclient"); // InitialContext を 利 用 して DataSource を 作 成 する DataSource ds = (DataSource)ctx.lookup("jdbc/DataSource1"); // DataSource を 利 用 して Connection を 作 成 する 12
Connection con = ds.getconnection(); InitialContext オブジェクトの lookup メソッドで 指 定 している DataSource1 がデータ ソース 名 です データソースを 登 録 するときにつけた 名 前 を 指 定 します InitialContext オブジェクトは ネーミングサービスの 情 報 の 起 点 を 表 すオブジェクトで す これはどのネーミングサービスを 利 用 するのかを 指 定 しています Interstage の 場 合 利 用 形 態 によっていくつかの 種 類 があります 上 記 の 例 は J2EE クライアントとして 実 行 す る 場 合 です 詳 細 は Interstage Application Server JSEE ユーザーズガイド を 参 照 してください Symfoware Server 専 用 のネーミングサービスを 利 用 する 場 合 Symfoware Server 専 用 のツールを 用 いて 登 録 したデータソースを 使 用 する 場 合 は 以 下 の ようにします ( 例 ) // ネーミングサービスの InitialContext を 作 成 する Hashtable env = new Hashtable(); env.put(context.initial_context_factory, "com.fujitsu.symfoware.jdbc2.jndisp.symcontextfactory"); env.put(context.provider_url,"sym://myhost:26600"); InitialContext ctx = new InitialContext(env); // InitialContext を 利 用 して DataSource を 作 成 する DataSource ds = (DataSource)ctx.lookup("jdbc/DataSource1"); 13
// DataSource を 利 用 して Connection を 作 成 する Connection con = ds.getconnection(); InitialContext オブジェクトの lookup メソッドで 指 定 している DataSource1 がデータ ソース 名 です データソースを 登 録 するときにつけた 名 前 を 指 定 します Symfoware Server のデータソース 登 録 ツールをネーミングサービスとして 使 用 することを 指 定 するには INITIAL_CONTEXT_FACTORY に 以 下 の 値 を 指 定 します com.fujitsu.symfoware.jdbc2.jndisp.symcontextfactory Symfoware Server 専 用 のネーミングサービスが 使 用 するポート 番 号 は デフォルトで 26600 (V9 までは 10326)です これは 変 更 することもできます 変 更 する 方 法 は マニュアル アプリケーション 開 発 ガイド(JDBC 編 ) を 参 照 してください 14
2.6 Connection Managerを 使 用 する 場 合 の 接 続 先 Symfoware Server Standard Edition Symfoware Server Enterprise Edition または Symfoware Server Enterprise Extended Edition の Connection Manager を 使 うと ロード シェアのクラスタシステムでのロードバランシング 機 能 や ホットスタンバイシステムで のコネクションリカバリ 機 能 などを 利 用 することができます Connection Manager を 利 用 する 場 合 は 接 続 先 のデータベースに 関 する 情 報 を APC 動 作 環 境 ファイルの 中 で SQL サーバ 情 報 として 記 述 しておきます Connection Manager を 利 用 する 環 境 で Java のアプリケーションから Symfoware Server を 利 用 する 場 合 接 続 先 のデータ 資 源 名 には APC 動 作 環 境 ファイルに 記 述 した SQL サーバ 名 を 指 定 します また Connection Manager を 利 用 する 場 合 アプリケーションと Symfoware Server が 異 な るコンピュータで 動 作 していても ローカル 接 続 を 指 定 します なお マルチ RDB の 場 合 でも RDB システム 名 はつけません Connection Manager を 利 用 する 場 合 の 接 続 先 は 以 下 のように 指 定 します DataSource を 使 う 場 合 ネーミングサービスにデータソースを 登 録 する 時 に [JDBC データソース 情 報 設 定 ] 画 面 の[データ 資 源 名 ]に SQL サーバ 名 を 指 定 してください DriverManager を 使 う 場 合 アプリケーションで 指 定 する URL のデータ 資 源 名 に SQL サーバ 名 を 指 定 してください ( 例 ) DriverManager.getConnection("jdbc.symfold:///SS","UID","PWD") ここで SS が SQL サーバ 名 です APC 動 作 環 境 ファイルには SS という 名 前 の SQL サーバの 情 報 が 記 載 されている 必 要 があります 詳 細 は マニュアル Connection Manager ユーザーズガイド の 5.1 コネクションのあ て 先 制 御 を 参 照 してください 15
第 3 章 SQL 文 の 準 備 16
3.1 SQL 文 を 表 すオブジェクト データベースに 処 理 を 依 頼 するには SQL 文 を 用 います Java アプリケーションで SQL 文 を 使 用 するには Statement オブジェクトか PreparedStatement オブジェクトを 作 成 します Statement オブジェクトや PreparedStatement オブジェクトには SQL 文 を 実 行 するための メソッドが 用 意 されています SELECT 文 を 実 行 する 場 合 は executequery メソッドを 用 います executequery メソッドを 実 行 すると 検 索 結 果 を 表 す ResultSet オブジェクトが 作 成 されます INSERT 文 UPDATE 文 DELETE 文 などのデータ 更 新 系 の SQL 文 を 実 行 する 場 合 は executeupdate メソッドを 用 います [ 補 足 ] execute メソッド Statement オブジェクトや PreparedStatement オブジェクトには SQL 文 を 実 行 するため のメソッドとして execute メソッドというものも 用 意 されています これは 実 行 される SQL 文 が 参 照 処 理 なのか 更 新 処 理 なのか 分 からない 場 合 や 1 個 の SQL 文 で 複 数 の ResultSet が 作 成 されるようなケースで 使 用 します 通 常 は execute メソッドを 使 用 することはありません 17
3.2 PreparedStatementクラスを 使 用 する 利 点 PreparedStatement クラスには Statement クラスに 比 べて 主 に 以 下 のような 利 点 がありま す SQL 文 の 中 に 動 的 に 変 更 できるパラメーターを 記 述 することができます SQL 文 で 指 定 する 検 索 条 件 の 値 や 格 納 するデータの 値 などを? と 記 述 しておき SQL 文 を 実 行 するときに 値 を 設 定 することができます そのため アプリケーションの 処 理 を 柔 軟 に 組 み 立 てることができます また SQL イ ンジェクションを 用 いた 不 正 アクセスを 防 ぐことにもつながり セキュリティの 向 上 に 役 立 ちます 同 じ SQL 文 を 何 度 も 実 行 する 場 合 SQL 文 の 解 析 は 最 初 の 1 回 だけで 済 みます Statement クラスを 使 用 する 場 合 は 同 じ SQL 文 を 実 行 する 場 合 でも 実 行 するたびに SQL 文 の 解 析 が 行 われます そのため 同 じ SQL 文 を 何 度 も 実 行 する 場 合 には アプリケーションの 性 能 が 向 上 し ます 18
3.3 SQL 文 の 中 でパラメーターを 使 う PreparedStatement オブジェクトを 用 いると SQL 文 の 中 でパラメーターを 使 用 することが できます SQL 文 の 中 でパラメーターを 使 用 する 部 分 には パラメーターを 設 定 するためのプレースホ ルダとして? を 記 述 します? の 部 分 には SQL 文 を 実 行 する 前 に 値 を 設 定 します 値 の 設 定 は PreparedStatement オブジェクトの setxxxx メソッドを 用 いて 行 います ( 例 ) // PreparedStatement オブジェクトを 作 成 する PreparedStatement pstmt = con.preparestatement( "SELECT ID,NAME FROM GENERAL.EMPLOYEE WHERE ID=?"); // 検 索 条 件 として ID 列 の 値 を 設 定 する pstmt.setint(1, 100); // SELECT 文 を 実 行 する ResultSet rs = pstmt.executequery(); ここで setint(1, 100) は 1 番 目 のパラメーターに 整 数 の 100 という 値 を 設 定 する ことを 意 味 します 値 を 設 定 するメソッドは データの 型 ごとに 用 意 されています ここでいうデータの 型 と は データベースの 列 の 型 ではなく Java アプリケーション 内 で 使 用 する Java のデータ 型 です 19
もし SQL 文 中 に 複 数 のパラメーターがある 場 合 は 前 から 順 に 1 番 目 2 番 目 という 番 号 で 指 定 します ( 例 ) // PreparedStatement オブジェクトを 作 成 する PreparedStatement pstmt = con.preparestatement( "INSERT INTO GENERAL.EMPLOYEE( ID,NAME) VALUES(?,?)"); // 1 番 目 のパラメーターに 4 という 数 値 を 設 定 する pstmt.setint(1,4); // 2 番 目 のパラメーターに"monkey"という 文 字 列 を 設 定 する pstmt.setstring(2,"monkey"); // INSERT 文 を 実 行 する pstmt.executeupdate(); 上 記 の 例 は 最 終 的 に 以 下 の SQL 文 を 実 行 します INSERT INTO GENERAL.EMPLOYEE(ID,NAME) VALUES(4,'monkey') 20
3.4 同 じSQL 文 を 何 度 も 使 う PreparedStatement オブジェクトを 用 いると 同 じ SQL 文 を 何 度 も 使 いまわすことができま す 何 度 も 同 じ SQL 文 を 実 行 する 場 合 SQL 文 の 解 析 は 最 初 の 1 回 だけで 済 みます そのため 毎 回 SQL 文 の 解 析 を 行 う Statement オブジェクトを 使 用 する 場 合 に 比 べて アプリケーシ ョンの 性 能 が 向 上 します ( 例 ) // PreparedStatement オブジェクトを 作 成 する PreparedStatement pstmt = con.preparestatement( "INSERT INTO GENERAL.EMPLOYEE( ID,NAME) VALUES(?,?)"); for( int iid=0 ; iid<100 ; iid++ ) { // 1 番 目 のパラメーターに iid の 値 を 設 定 する pstmt.setint(1,iid); // 2 番 目 のパラメーターに 配 列 sname に 格 納 されている 文 字 列 を 設 定 する pstmt.setstring(2,sname[iid]); // INSERT 文 を 実 行 する pstmt.executeupdate(); } 21
この 例 では ループの 中 で 同 じ SQL 文 をパラメーターを 変 更 しながら 使 いまわしています SQL 文 の 解 析 は 最 初 に preparestatement メソッドを 実 行 したときにのみ 行 われます この 処 理 を Statement オブジェクトを 用 いて 行 うと 以 下 のようになります この 例 では ループ 内 で executeupdate メソッドを 実 行 するたびに SQL 文 の 解 析 が 行 われます ( 例 ) // Statement オブジェクトを 作 成 する Statement stmt = con.createstatement(); for( int iid=0 ; iid<100 ; iid++ ) { // SQL 文 を 組 み 立 てる String sql = "INSERT INTO GENERAL.EMPLOYEE(ID,NAME) VALUES(" + String.valueOf(iID) + ",'" + sname[iid] + "')"; } // INSERT 文 を 実 行 する stmt.executeupdate(sql); 22
第 4 章 データベースの 検 索 23
4.1 検 索 の 実 行 PreparedStatement クラスを 用 いて SELECT 文 の 検 索 条 件 にパラメーターを 用 いて 何 度 も 同 じ 検 索 を 行 う 例 を 以 下 に 示 します SELECT 文 の 解 析 は preparestatement メソッドを 実 行 したときに 1 回 だけ 行 われ その 後 の ループでは 同 じ SELECT 文 を 使 いまわしています ( 例 ) // Symfoware Server のネーミングサービスを 利 用 する 準 備 を 行 う Hashtable env = new Hashtable(); env.put(context.initial_context_factory, "com.fujitsu.symfoware.jdbc2.jndisp.symcontextfactory"); env.put(context.provider_url,"sym://myhost:26600"); InitialContext ctx = new InitialContext(env); // InitialContext を 利 用 して DataSource を 作 成 する DataSource ds = (DataSource)ctx.lookup("jdbc/DataSource1"); // DataSource を 利 用 してデータベースに 接 続 する Connection con = ds.getconnection(); // 自 動 コミットを 解 除 する con.setautocommit(false); 24
// PreparedStatement オブジェクトを 作 成 する PreparedStatement pstmt = con.preparestatement( "SELECT ID,NAME FROM GENERAL.EMPLOYEE WHERE ID=?"); // SELECT 文 を 実 行 して ResultSet オブジェクトを 得 る for( int loopcount=0 ; loopcount <100 ; loopcount ++ ) { // パラメーターに 検 索 条 件 を 設 定 する pstmt.setint(1, loopcount); // SELECT 文 を 実 行 する ResultSet rs = pstmt.executequery(); // ResultSet からデータを 取 り 出 す while (rs.next()) { // ID と NAME の 値 を 取 り 出 す int iid = rs.getint(1); String sname = rs.getstring(2); // 取 り 出 した 値 を 表 示 させる System.out.println("ID = " + iid); System.out.println("NAME = " + sname); 25
} // ResultSet オブジェクトを 破 棄 する rs.close(); } // PreparedStatement オブジェクトを 破 棄 する pstmt.close(); // SELECT 文 をコミットする con.commit(); // データベースから 切 断 する con.close(); [ 補 足 ] PreparedStatement には 利 点 がありますが 常 に 利 点 があるわけではありません 内 容 が 決 まって いる SQL 文 を 1 回 だけ 実 行 する 場 合 など PreparedStatement を 使 用 する 意 味 がない 場 合 には Statement を 用 いた 方 がプログラムが 単 純 になります 26
第 5 章 検 索 結 果 の 取 り 出 し 27
5.1 ResultSetの 基 本 操 作 Statement オブジェクトや PreparedStatement オブジェクトを 用 いて SELECT 文 を 実 行 する と 検 索 結 果 の 表 を 表 す ResultSet オブジェクトが 作 成 されます ResultSet オブジェクトには getstring メソッドや getint メソッドなど 結 果 表 の 列 の 値 を 取 り 出 すためのメソッドが 用 意 されています これらのメソッドを getter メソッドと 呼 びます ResultSet オブジェクトには 結 果 表 の 特 定 の 1 行 を 参 照 するためのカーソルが 備 わってい ます getter メソッドを 用 いることで カーソルが 位 置 づけられている 行 から データを 取 り 出 すことができます ResultSet オブジェクトから 検 索 結 果 を 取 り 出 す 処 理 は 以 下 の 手 順 で 行 います (1) カーソルを 検 索 結 果 の 表 の 中 のある 行 に 位 置 づける (2) ResultSet オブジェクトの getter メソッドを 用 いて 列 の 値 を 取 り 出 す 28
5.2 カーソルを 移 動 させる 方 法 ResultSet オブジェクトが 表 す 結 果 表 には 行 番 号 がつけられています 最 初 の 行 の 行 番 号 は 1 2 行 目 の 行 番 号 は 2 になります ResultSet オブジェクトが 作 成 された 時 点 では カーソルは 行 番 号 0 に 位 置 づけられていま す 0 番 目 の 行 は 存 在 しないので この 状 態 ではデータを 取 り 出 すことはできません 結 果 表 からデータを 取 り 出 すには まずカーソルをどこかの 行 に 移 動 させる 必 要 がありま す デフォルトの ResultSet では カーソルは 順 方 向 に 1 行 ずつ 移 動 させることのみできます カーソルを 移 動 させるには next メソッドを 実 行 します カーソルが 最 終 行 まで 達 した 状 態 で next メソッドを 実 行 すると false が 返 ります それ によってアプリケーションは 結 果 表 からすべてのデータを 取 り 出 し 終 わったことを 知 る ことができます 29
5.3 カーソルを 自 由 に 動 かす 方 法 デフォルトのカーソルのタイプは TYPE_FORWARD_ONLY です ResultSet のカーソルには 全 部 で 3 つのタイプがあります TYPE_FORWARD_ONLY デフォルトのカーソルタイプです next メソッドを 用 いて 順 方 向 に 1 行 ずつカーソ ルを 移 動 させることのみ 可 能 です TYPE_SCROLL_INSENSITIVE 自 由 に 移 動 させることができるカーソルタイプです TYPE_SCROLL_SENSITIVE 自 由 に 移 動 させることができるカーソルタイプです Symfoware Server ではいずれのタイプを 選 択 しても ResultSet から 取 り 出 されるデータ は ResultSet を 作 成 した 時 点 のものになります カーソルのタイプに TYPE_SCROLL_INSENSITIVE または TYPE_SCROLL_SENSITIVE を 指 定 する と カーソルを 自 由 に 動 かすことができるようになります カーソルのタイプは createstatement メソッドまたは preparestatement メソッドを 実 行 するときに 引 数 で 指 定 します これらのメソッドの 仕 様 上 カーソルのタイプを 単 独 で 指 定 することはできず ResultSet の 更 新 可 能 性 の 指 定 とセットで 指 定 する 必 要 があります 下 記 の 例 では カーソルのタイプに TYPE_SCROLL_INSENSITIVE を 指 定 しています ( 例 ) // Statement オブジェクトを 作 成 する Statement stmt = con.createstatement( java.sql.resultset.type_scroll_insensitive, 30
java.sql.resultset.concur_read_only); 31
5.4 カーソルを 動 かすためのメソッド カーソルを 移 動 させるには ResultSet オブジェクトのメソッドを 実 行 します メソッドに は 以 下 のものがあります absolute メソッド カーソルを ResultSet オブジェクト 内 の 指 定 された 行 番 号 の 行 に 移 動 します afterlast メソッド カーソルを ResultSet オブジェクトの 最 終 行 の 直 後 に 移 動 します beforefirst メソッド カーソルを ResultSet オブジェクトの 先 頭 行 の 直 前 に 移 動 します つまり ResultSet オブジェクトを 作 成 したときの 初 期 位 置 ( 行 番 号 0)に 移 動 します first メソッド カーソルをこの ResultSet オブジェクト 内 の 先 頭 行 ( 行 番 号 1)に 移 動 します last メソッド カーソルを ResultSet オブジェクト 内 の 最 終 行 に 移 動 します next メソッド カーソルを 現 在 の 位 置 の 1 行 下 に 移 動 します previous メソッド カーソルをこの ResultSet オブジェクト 内 の 前 の 行 に 移 動 します relative メソッド カーソルを 正 または 負 の 相 対 行 数 だけ 移 動 します 32
5.5 ResultSetの 保 持 機 能 ResultSet オブジェクトは トランザクションが 終 了 すると 自 動 的 にクローズされます しかし トランザクションが 終 了 したあとで 検 索 結 果 を 参 照 したい 場 合 もあります 例 えば 以 下 のようなケースです 検 索 結 果 を 参 照 しながら 別 の 表 を 更 新 している このとき 更 新 処 理 をこまめにコ ミットしたい 更 新 をコミットすると ResultSet もクローズされてしまう これを 避 けるために ResultSet を 保 持 したい 場 合 検 索 結 果 を 順 次 に 画 面 表 示 させるなど 検 索 結 果 のデータがいつ 不 要 になるか 分 から ない ResultSet は 必 要 だが トランザクションは 早 めに 終 了 させておきたい 場 合 このような 場 合 トランザクション 終 了 後 も ResultSet をクローズせずに 保 持 することが できます ResultSet の 保 持 機 能 は Symfoware Server V10 からサポートされています ResulSet の 保 持 機 能 を 使 用 するかどうかは Connection オブジェクトで 設 定 します 以 下 のように Connection オブジェクトの setholdability メソッドで ResultSet を 保 持 する ことを 宣 言 します ( 例 ) // データベースに 接 続 する Class.forName("com.fujitsu.symfoware.jdbc.SYMDriver"); Connection con = DriverManager.getConnection( "jdbc:symfold:///company","uid", "PWD"); 33
// 自 動 コミットを 解 除 し ResultSet 保 持 機 能 の 使 用 を 宣 言 する con.setautocommit(false); con.setholdability(resultset.hold_cursors_over_commit); // 検 索 を 実 行 し トランザクションをコミットする Statement stmt = con.createstatement(); ResultSet rs = stmt.executequery( "SELECT ID,NAME FROM GENERAL.EMPLOYEE "); con.commit(); // トランザクション 終 了 後 に ResultSet を 参 照 する while (rs.next()) { /* ID と NAME の 値 を 取 り 出 す */ int iid = rs.getint(1); String sname = rs.getstring(2); /* 取 り 出 した 値 を 表 示 させる */ System.out.println("ID = " + iid); System.out.println("NAME = " + sname); } rs.close(); 34
setholdability メソッドで 以 下 のいずれかを 指 定 できます CLOSE_CURSORS_AT_COMMIT 現 在 のトランザクションがコミットされたときに ResultSet オブジェクトがクローズ されることを 示 します デフォルトでは CLOSE_CURSORS_AT_COMMIT が 指 定 されたこと になります HOLD_CURSORS_OVER_COMMIT 現 在 のトランザクションがコミットされたときに ResultSet オブジェクトがクローズ されずに 保 持 されることを 示 します 35
5.6 ResultSetの 保 持 機 能 を 使 う 上 での 注 意 ResultSet 保 持 機 能 を 使 用 する 場 合 は 以 下 の 点 に 注 意 してください ResultSet 保 持 機 能 を 使 用 する 場 合 イルシデーションロックの 機 能 は 使 用 できません イルシデーションロックを 明 示 的 に 使 用 すると 構 文 エラーになります Symfoware Server Standard Edition Symfoware Server Enterprise Edition また は Symfoware Server Enterprise Extended Edition において 動 作 環 境 ファイルや ctuneparam で DSO_LOCK パラメーターを 設 定 すると イルシデーションロックが 使 用 で きなくなります ResultSet 保 持 機 能 は 暗 黙 的 にイルシデーションロックを 使 用 します そのため イル シデーションロックが 使 用 できないような 設 定 にすると 検 索 処 理 がエラーになりま す また ResultSet 保 持 機 能 と ResultSet を 更 新 可 能 とする 機 能 は 同 時 には 使 用 できませ ん [ 補 足 ] Symfoware Server の 排 他 制 御 データベースでは 同 時 に 複 数 のユーザーが 同 じデータにアクセスすることがあります このとき データの 検 索 や 更 新 が 同 時 に 行 われても ユーザーにとって 矛 盾 のないデータになっている 必 要 が あります そのために Symfoware Server はロックを 用 いた 排 他 制 御 を 行 っています アクセス 中 のデータを ロックすることによって 同 じデータが 同 時 に 更 新 されることを 防 いだり 参 照 中 のデータが 別 の ユーザーによって 不 用 意 に 変 更 されることを 防 いだりします データをロックすることによってデータの 矛 盾 を 防 ぐことができますが 完 全 にロックしてしまう と 複 数 の 処 理 を 同 時 に 実 行 することができなくなってしまいます そこで ロックの 強 さやロッ クしている 期 間 を 調 整 することができるようになっています 36
Symfoware Server では 排 他 制 御 の 調 整 は 以 下 の 方 法 で 行 うことができます 独 立 性 水 準 トランザクション 単 位 にロックのかかりかたを 調 整 できます 独 立 性 水 準 を 設 定 するには Connection オブジェクトの settransactionisolation メソッドを 用 います イルシデーションロック SQL 文 単 位 にロックのかかりかたを 調 整 できます イルシデーションロックを 設 定 するには SQL 文 に WITH OPTION LOCK_MODE 句 を 付 加 します イルシデーションロックの 設 定 は 独 立 性 水 準 の 設 定 よりも 優 先 されます [ 補 足 ] ResultSet 保 持 機 能 を 有 効 にした 状 態 で SELECT 文 を 実 行 すると SELECT 文 に 自 動 的 に 以 下 が 付 加 されます WITH OPTION LOCK_MODE(FREE LOCK) これは Symfoware Server のイルシデーションロックという 機 能 です イルシデーションロッ クを 用 いると データの 排 他 制 御 を SQL 文 ごとに 指 定 することができます FREE LOCK を 指 定 すると SELECT 文 の 実 行 が 完 了 した 時 点 で 検 索 対 象 のデータに 対 するロッ クが 解 除 されることを 意 味 します なお Symfoware Server Standard Edition Symfoware Server Enterprise Edition または Symfoware Server Enterprise Extended Edition において PRECEDENCE(1)を 指 定 した SEQUENTIAL 構 造 の 場 合 および Symfoware Server Lite Edition の 場 合 は FREE LOCK を 指 定 すると 一 定 条 件 下 で 資 源 を 占 有 しません CURSOR_MODE(HOLD) トランザクションが 終 了 したあともカーソルをオープンしたままにすることを 指 定 します 37
38
第 6 章 データの 更 新 39
6.1 更 新 可 能 なResultSetオブジェクトの 作 成 ResultSet オブジェクトは SELECT 文 による 検 索 結 果 を 表 すオブジェクトですが 一 定 の 条 件 を 満 たしていれば ResultSet オブジェクトを 用 いて 検 索 結 果 の 行 を 更 新 することがで きます ResultSet を 用 いたデータの 更 新 機 能 は Symfoware Server V10 からサポートさ れています ResultSet を 用 いたデータの 更 新 を 行 うには ResultSet オブジェクトを 更 新 可 能 なものと して 作 成 する 必 要 があります そのためには createstatement メソッドまたは preparestatement メソッドを 実 行 するときに 引 数 で 指 定 します これらのメソッドの 仕 様 上 ResultSet の 更 新 可 能 性 を 単 独 で 指 定 することはできず カーソルのタイプの 指 定 と セットで 指 定 する 必 要 があります ResultSet の 更 新 可 能 性 の 指 定 には 以 下 の 2 種 類 があります CONCUR_READ_ONLY ResultSet オブジェクトが 更 新 できないことを 指 定 します デフォルトでは CONCUR_READ_ONLY が 指 定 された 状 態 になります CONCUR_UPDATABLE ResultSet オブジェクトが 更 新 できることを 指 定 します 下 記 の 例 では ResultSet を 更 新 可 能 とするように CONCUR_UPDATABLE を 指 定 しています ( 例 ) // Statement オブジェクトを 作 成 する Statement stmt = con.createstatement( java.sql.resultset.type_forward_only, java.sql.resultset.concur_updatable); 40
CONCUR_UPDATABLE を 指 定 しても 常 に ResultSet が 更 新 可 能 になるわけではありません 例 えば SELECT 文 で 複 数 の 表 を 結 合 している 場 合 は ResultSet を 用 いた 更 新 はできませ ん また カーソルタイプにスクロール 可 能 カーソル(TYPE_SCROLL_INSENSITIVE や TYPE_SCROLL_SENSITIVE)を 指 定 した 場 合 は ResultSet は 更 新 できません スクロール 可 能 カーソルを 指 定 しても SELECT 文 に FOR UPDATE 句 を 付 加 している 場 合 は ResultSet を 更 新 することができます ResultSet を 用 いたデータの 更 新 が 可 能 かどうかは カーソルが 更 新 可 能 かどうかによりま す CONCUR_UPDATABLE を 指 定 しても カーソルが 読 取 専 用 になっている 場 合 には ResultSet を 更 新 できません カーソルが 読 取 専 用 になる 条 件 は マニュアル SQL リファレンス の DECLARE CURSOR(カ ーソル 宣 言 ) を 参 照 してください 41
6.2 ResultSetオブジェクトを 用 いたデータの 更 新 ResultSet オブジェクトには 列 の 値 を 更 新 するためのメソッドが データ 型 ごとに 用 意 さ れています このメソッドは updatexxxx という 形 式 の 名 前 になっています 例 えば 文 字 列 型 のデータを 更 新 する 場 合 には updatestring メソッドを 用 います これらのメソッド を updater メソッドと 呼 びます ResultSet オブジェクトを 用 いてデータを 更 新 するには 以 下 のようにします (1) CONCUR_UPDATABLE を 指 定 して Statement オブジェクトや PreparedStatement オブジェ クトを 作 成 する (2) Statement オブジェクトや PreparedStatement オブジェクトの executequery メソッド を 用 いて 検 索 を 行 い ResultSet オブジェクトを 作 成 する (3) ResultSet のカーソルを 更 新 したい 行 に 位 置 づける (4) ResultSet の updater メソッド 群 を 用 いて 列 の 値 を 更 新 する (5) ResultSet の updaterow メソッドを 用 いて 行 を 実 際 に 更 新 する (6) 更 新 をコミットする ( 例 ) import java.sql.*; import java.io.*; public class test { 42
public static void main(string args[]) { try { // データベースに 接 続 する Class.forName("com.fujitsu.symfoware.jdbc.SYMDriver"); Connection con = DriverManager.getConnection( "jdbc:symfold:///db","uid", "PWD"); con.setautocommit(false); // Statement オブジェクトを 作 成 する Statement stmt = con.createstatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); // 検 索 を 行 い ResultSet オブジェクトを 作 成 する ResultSet rs = stmt.executequery( "SELECT ID,NAME FROM GENERAL.EMPLOYEE"); // ResultSetを 参 照 して 条 件 に 合 う 行 を 更 新 する int iid = 0; String sname = null; 43
while(rs.next()) { iid = rs.getint(1); sname = rs.getstring(2); System.out.println("ID = " + iid); System.out.println("NAME = " + sname); if(iid==3) { rs.updatestring(2,"leopard"); rs.updaterow(); } } // 更 新 をコミットして データベースから 切 断 する stmt.close(); con.commit(); con.close(); } catch (SQLException e) { System.out.println("ERROR MESSAGE : " + e.getmessage()); System.out.println("SQLSTATE : " + e.getsqlstate()); System.out.println("ERROR CODE : " + e.geterrorcode()); 44
e.printstacktrace(); } catch (Exception e) { System.out.println("ERROR MESSAGE : " + e.getmessage()); e.printstacktrace(); } } } [ 補 足 ] 一 般 に オブジェクトに 値 を 設 定 するメソッドを setter メソッド オブジェクトから 値 を 取 り 出 す メソッドを getter メソッド オブジェクトの 保 持 している 値 を 更 新 するメソッドを updater メソッ ドと 呼 びます [ 補 足 ] 更 新 可 能 な ResultSet を 作 成 しても そのデータには 更 新 ロックは 掛 けられていません 更 新 ロッ クがかかるのは updaterow メソッドを 実 行 したときです 実 際 の 更 新 を 行 うまでは 独 立 性 水 準 やイルシデーションロックの 設 定 によって ロックのかかり 方 が 変 わります デフォルトの 状 態 では 読 み 取 り 用 のロックがかかっています そのため 更 新 可 能 な ResultSet を 作 っても 他 のトランザクションから 同 じデータを 参 照 することができます データを 参 照 する 45
ことによって 他 のトランザクションから 読 み 取 り 用 のロックが 掛 けられるため ResultSet を 用 いたデータの 更 新 を 実 行 すると ロック 解 除 待 ちとなります SELECT 文 に FOR UPDATE 句 を 付 加 すると 最 初 から 更 新 ロックがかかります 他 のトランザクショ ンによる 参 照 がロック 解 除 待 ちになるため 他 のトランザクションの 終 了 を 待 つことなくデータの 更 新 を 行 うことができます 46
6.3 カーソルを 使 用 した 更 新 ResultSet を 用 いたデータの 更 新 機 能 は Symfoware Server V10 以 降 でサポートされてい ます ResultSet の 更 新 機 能 を 用 いずに 検 索 結 果 を 参 照 してデータを 更 新 するには ResultSet オブジェクトの getcursorname メソッドを 用 いた 方 法 があります この 方 法 は V9 までのバージョンでも 利 用 可 能 です UPDATE 文 や DELETE 文 は カーソルを 位 置 づけた 行 を 更 新 することができます ResultSet のカーソルを 使 って UPDATE 文 や DELETE 文 で 目 的 の 行 に 位 置 づけることができます ( 例 ) // 更 新 対 象 を 検 索 ResultSet rs1 = null; PreparedStatement pstmt1 = con.preparestatement( "SELECT ID,NAME FROM GENERAL.EMPLOYEE FOR UPDATE"); rs1 = pstmt1.executequery(); // カーソル 名 を 取 得 String cursorname = rs1.getcursorname(); while(rs1.next()) { // UPDATE 文 の WHERE CURRENT OF 句 にカーソル 名 を 指 定 してデータ 更 新 PreparedStatement pstmt2 = null; pstmt2 = con.preparestatement( 47
"UPDATE GENERAL.EMPLOYEE SET NAME ='human' WHERE CURRENT OF " + cursorname ); } int ret = pstmt2.executeupdate(); pstmt2.close(); 48
6.4 RowIDを 使 用 したデータ 更 新 RowID とは データベース 内 の 任 意 の 表 の 行 を 一 意 に 識 別 することのできる 値 です RowID の 実 体 が 何 であるかは データベースソフトによって 異 なります Symfoware Server の 場 合 RowID のことを 行 識 別 子 と 呼 びます これは 24 バイトの 値 で 行 の 物 理 的 なアドレス を 示 します 同 じデータに 何 度 もアクセスする 場 合 その 行 の 物 理 的 なアドレスが 分 かっていれば 処 理 を 高 速 に 行 うことができます 対 象 データがどこにあるか 探 さなくても 直 接 場 所 を 指 定 してアクセスできるからです 行 識 別 子 は SELECT 文 で 値 を 取 り 出 したり UPDATE 文 の WHERE 句 に 条 件 として 指 定 したりす ることができます その 際 の 列 名 にあたるのは ROW_ID という 語 です 以 下 のような SQL 文 で 行 識 別 子 を 扱 うことができます ( 例 ) SELECT ROW_ID FROM GENERAL.EMPLOYEE WHERE NAME=lion 上 記 の 例 では NAME 列 が lion である 行 を 検 索 し その 行 の 行 識 別 子 (ROW_ID)を 取 り 出 しています ( 例 ) UPDATE GENERAL.EMPLOYEE SET NAME='tiger' WHERE ROW_ID=? 上 記 の 例 では ROW_ID が 指 定 した 値 である 行 の NAME 列 を tiger に 変 更 しています 49
このように SQL 文 中 では ROW_ID という 語 を 用 いて 行 識 別 子 を 扱 うことができます これを Java アプリケーションで 利 用 するには ResultSet オブジェクトの getrowid メソッ ドや PreparedStatement オブジェクトの setrowid メソッドを 用 います ROW_ID は SQL 文 中 では 列 名 として 扱 われるので 通 常 の 列 の 値 と 同 様 に 行 識 別 子 を 操 作 す ることができます 行 識 別 子 を 用 いた 更 新 は Symfoware Server V10 からサポートされています ( 例 ) // SELECT 文 を 表 す Statement オブジェクトを 作 成 する Statement stmt = con.createstatement(); // 行 識 別 子 を 検 索 する ResultSet rs = stmt.executequery ("SELECT ROW_ID FROM GENERAL.EMPLOYEE WHERE NAME='lion'"); RowId rowid = null; // ResultSet の getrowid を 用 いて 行 識 別 子 を 取 り 出 す while(rs.next()) { rowid = rs.getrowid(1); } // UPDATE 文 を 表 す PreparedStatement オブジェクトを 作 成 する 50
PreparedStatement pstmt = con.preparestatement ROW_ID=?"); ("UPDATE GENERAL.EMPLOYEE SET NAME='tiger' WHERE // 検 索 条 件 のパラメーターに 先 ほど 取 り 出 した 行 識 別 子 を 設 定 する pstmt.setrowid(1,rowid); // UPDATE 文 を 実 行 する pstmt.executeupdate(); // オブジェクトをクローズして 更 新 をコミットする rs.close(); stmt.close(); pstmt.close(); con.commit(); 51
6.5 RowIDを 使 用 したデータ 更 新 の 注 意 点 行 識 別 子 を 使 用 する 場 合 以 下 の 点 に 注 意 してください 取 り 出 した 行 識 別 子 は そのトランザクション 内 で 再 検 索 または 更 新 に 使 用 すること ができます ただし トランザクションの 独 立 性 水 準 によっては 同 一 トランザクション 内 において も 同 じ 行 を 検 索 できなかったり 異 なる 行 を 更 新 してしまったりすることがありま す これは 独 立 性 水 準 によって 排 他 制 御 によるデータの 占 有 期 間 が 変 わるためです 不 都 合 を 避 けるためには トランザクションで 使 用 する 独 立 性 水 準 に 問 題 を 起 こさ ないものを 指 定 するなどして 対 処 してください 独 立 性 水 準 SERIALIZABLE REPEATABLE READ READ COMMITTED 行 識 別 子 を 指 定 した 操 作 同 一 行 に 対 する 操 作 が 保 証 されます 同 一 行 に 対 する 操 作 が 保 証 されます 以 下 のいずれかの 条 件 で 取 得 した 行 識 別 子 は 再 検 索 で 異 な る 行 を 識 別 することがあります トランザクションアクセスモードが READ ONLY カーソルの 更 新 可 能 性 句 が READ ONLY Symfoware Server Standard Edition Symfoware Server Enterprise Edition または Symfoware Server Enterprise Extended Edition において PRECEDENCE(1)を 指 定 した SEQUENTIAL 構 造 の 場 合 および Symfoware Server Lite Edition の 場 合 以 下 のいずれかの 条 件 で 取 得 した 行 識 別 子 は 再 検 索 で 異 なる 行 を 識 別 することがあります トランザクションアクセスモードが READ ONLY カーソルの 更 新 可 能 性 句 が READ ONLY または 省 略 READ UNCOMMITTED 再 検 索 で 異 なる 行 を 識 別 することがあります 52
取 り 出 した 行 識 別 子 を 他 のトランザクションで 再 検 索 または 更 新 に 利 用 すると 同 じ 行 を 検 索 できなかったり 異 なる 行 を 更 新 してしまったりすることがあります このような 場 合 行 識 別 子 を 取 り 出 したときに 行 のデータも 同 時 に 取 り 出 しておき 行 識 別 子 を 利 用 して 更 新 する 前 に 行 識 別 子 で 再 検 索 して 行 のデータが 他 のトランザ クションにより 変 更 されていないかどうかを 調 べる 必 要 があります 事 象 検 索 データなし 前 回 の 検 索 結 果 と 値 が 異 なる 原 因 該 当 行 が 他 のトランザクションによって 削 除 または 更 新 されています 他 のトランザクションにより 行 が 更 新 されています または 他 のトランザクションにより 行 が 削 除 された 後 別 の 行 が 挿 入 されています 53
6.6 バッチ 更 新 バッチ 更 新 の 機 能 を 使 用 すると 複 数 の 更 新 系 の SQL 文 を 一 括 して 実 行 することができま す 一 括 して 実 行 することで 性 能 向 上 を 図 ることができます 例 えば 以 下 のような INSERT 文 を 100 回 実 行 するケースを 考 えてみます ( 例 ) INSERT INTO GENERAL.EMPLOYEE(ID,NAME) VALUES(?,?) これを Statement オブジェクトを 用 いて 実 行 するには 100 個 の INSERT 文 を 文 字 列 として 組 み 立 て 1 個 ずつ executequery メソッドを 用 いて 実 行 します 格 納 するデータが 異 なる だけの 同 じ INSERT 文 であっても 毎 回 SQL 文 の 解 析 が 行 われます PreparedStatement オブジェクトを 用 いれば SQL 文 の 解 析 は 最 初 の 1 回 だけで 済 みますが 100 個 の INSERT 文 を 1 個 ずつ executequery メソッドを 用 いて 実 行 しなくてはならない 点 は 変 わりません バッチ 更 新 機 能 を 用 いると 100 個 分 の INSERT 文 を 溜 め 込 んで 1 回 のメソッド 呼 び 出 し で 一 括 して 実 行 させることができます このとき クライアントとデータベースサーバと の 通 信 は 1 回 だけで 済 みます 1 回 ずつ SQL 文 を 送 信 して 結 果 を 受 信 する 場 合 に 比 べて 性 能 向 上 を 期 待 できます バッチ 更 新 機 能 は Symfoware Server V10 からサポートされています バッチ 更 新 には 以 下 の 2 種 類 があります 54
異 なる SQL 文 を 溜 め 込 んで 一 括 して 実 行 するパターン 同 一 の SQL のプレースホルダに 設 定 するデータを 溜 め 込 んで 一 括 して 実 行 するパタ ーン バッチ 更 新 で 実 行 する SQL 文 でエラーが 発 生 すると バッチ 更 新 全 体 がロールバックされ ます 55
6.7 異 なるSQL 文 を 一 括 実 行 Statement オブジェクトを 用 いたバッチ 更 新 機 能 です Statement オブジェクトの addbatch メソッドを 用 いて 複 数 の INSERT 文 UPDATE 文 DELETE 文 を 溜 め 込 みます 溜 め 込 んだ SQL 文 を 一 括 して 実 行 するには Statement オブジェクトの executebatch メソ ッドを 用 います 以 下 の 例 では INSERT 文 UPDATE 文 DELETE 文 からなるバッチ 処 理 を 実 行 しています 3 個 の SQL 文 を addbatch メソッドで 溜 め 込 みます その 後 executebatch メソッドを 実 行 し て SQL 文 を 一 括 して 実 行 しています ( 例 ) // 自 動 コミットを 解 除 する con.setautocommit(false); // Statement オブジェクトを 作 成 する Statement stmt = con.createstatement(); // SQL 文 を 溜 め 込 む stmt.addbatch("insert INTO GENERAL.EMPLOYEE(ID,NAME) VALUES(1,'tiger')"); ID=2"); stmt.addbatch("update GENERAL.EMPLOYEE SET NAME='monkey' WHERE stmt.addbatch("delete FROM GENERAL.EMPLOYEE WHERE ID=3"); 56
// バッチ 更 新 を 実 行 する int[] upc = stmt.executebatch(); // 更 新 をコミットして データベースから 切 断 する stmt.close(); con.commit(); con.close(); 57
6.8 同 一 のSQL 文 をパラメーターを 変 えて 一 括 実 行 PreparedStatement オブジェクトを 用 いたバッチ 更 新 機 能 です PreparedStatement オブジェクトの addbatch メソッドを 用 いて プレースホルダに 設 定 す るデータの 値 を 溜 め 込 みます SQL 文 は 1 種 類 だけですが パラメーターの 値 が 異 なる 複 数 の SQL 文 となります 溜 め 込 んだ SQL 文 を 一 括 して 実 行 するには PreparedStatement オブジェクトの executebatch メソッドを 用 います 以 下 の 例 では 100 個 の INSERT 文 を 実 行 しています INSERT 文 で 格 納 するデータはプレー スホルダで 記 述 しておき INSERT 文 100 個 分 の 格 納 データの 組 を addbatch メソッドで 溜 め 込 みます その 後 executebatch メソッドを 実 行 して 100 個 の INSERT 文 を 一 括 して 実 行 しています ( 例 ) // 自 動 コミットを 解 除 する con.setautocommit(false); // PreparedStatement オブジェクトを 作 成 する PreparedStatement pstmt = con.preparestatement( "INSERT INTO GENERAL.EMPLOYEE(ID,NAME) VALUES(?,?)"); // ループしながら INSERT 文 のパラメーターを 設 定 する 58
for( int iid=0 ; iid<100 ; iid++ ) { // 1 番 目 のパラメーターに iid の 値 を 設 定 する pstmt.setint(1, iid); // 2 番 目 のパラメーターに 配 列 sname に 格 納 されている 文 字 列 を 設 定 する pstmt.setstring(2, sname[iid]); // バッチ 処 理 として 登 録 する pstmt.addbatch(); } // バッチ 更 新 を 実 行 する int[] upc = pstmt.executebatch(); // 更 新 をコミットして データベースから 切 断 する pstmt.close(); con.commit(); con.close(); 59
第 7 章 例 外 処 理 と 後 始 末 60
7.1 例 外 処 理 JDBC の 処 理 でエラーが 発 生 すると 例 外 として SQLException がスローされます この 例 外 はアプリケーションで catch する 必 要 があります ここで 注 意 しなければならないのは どのエラーもすべて SQLException で 表 される とい う 点 です エラーの 内 容 を 調 べるには SQLException オブジェクトから エラー 情 報 を 取 り 出 して 調 べる 必 要 があります SQLException から 取 り 出 せるエラー 情 報 と 取 り 出 す 方 法 は 以 下 のとおりです エラーメッセージ SQLException オブジェクトの getmessage メソッドを 用 いて 取 り 出 すことができます これは Symfoware Server のメッセージです メッセージ 番 号 とメッセージ 本 文 からな ります メッセージの 意 味 と 対 処 方 法 は マニュアル メッセージ 集 から 調 べることができ ます SQLSTATE SQLException オブジェクトの getsqlstate メソッドを 用 いて 取 り 出 すことができます 必 要 に 応 じてアプリケーション 内 で SQLSTATE の 値 を 調 べ エラー 処 理 を 行 ってくださ い 例 えば トランザクションをロールバックして オブジェクトをクローズしたあと トランザクションの 再 実 行 を 行 うか あるいは 接 続 をクローズしてアプリケーション を 終 了 するか といったことを 決 定 するために SQLSTATE の 値 を 利 用 することができ ます エラーコード SQLException オブジェクトの geterrorcode メソッドを 用 いて 取 り 出 すことができます エラーコードはデータベースベンダの 固 有 の 情 報 です Symfoware Server では SQLSTATE が S1000 の 場 合 に Vendor エラーメッセージとして 設 定 されています それ 以 外 の 場 合 は メッセージ 番 号 が 設 定 されています 61
Vendor エラーメッセージについては マニュアル アプリケーション 開 発 ガイド(JDBC 編 ) の Vendor エラーメッセージ を 参 照 してください Symfowre Server V10 以 降 で JDBC4.0 準 拠 の JDBC ドライバを 使 用 している 場 合 JDBC の API のうち Symfoware Server がサポートしていない API を 使 用 すると 例 外 として SQLFeatureNotSupportedExcepiton が 発 生 します JDBC の API の 中 には Symfoware Server ではサポートしていないものもあるので 注 意 して ください 62
7.2 オブジェクトのクローズ 不 要 になった JDBC のオブジェクトは 早 めにクローズしてください エラーが 発 生 した 場 合 エラー 処 理 の 中 で 必 要 に 応 じて Statement オブジェクトや Connection オブジェクトなどのクローズ 処 理 を 行 ってください close メソッドでエラーが 発 生 した 場 合 にも SQLException が 発 生 するため エラー 処 理 の 中 でも 例 外 を catch する 必 要 があります [ 補 足 ] アプリケーションのプロセスが 終 了 した 場 合 は すべてのオブジェクトは 消 滅 し データベースへ の 接 続 など Symfoware Server 側 のリソースも 回 収 されます 63