A JDBCリファレンス情報
この付録では、Java Database Connectivity(JDBC)リファレンス詳細情報について説明します。内容は次のとおりです。
A.1 サポートされているSQLとJDBCデータ型のマッピング
この項では、特定のSQLデータ型が有効なマッピングを持つ可能性があるすべてのJava型を示します。
Oracle JDBCドライバでは、これらの非デフォルト・マッピングをサポートしています。たとえば、SQL CHAR
データをoracle.sql.CHAR
オブジェクトとしてインスタンス化するには、getCHAR
メソッドを使用します。java.math.BigDecimal
オブジェクトとしてインスタンス化するには、getBigDecimal
メソッドを使用します。
ノート:
oracle.jdbc.OracleData
がイタリックで表示されているクラスは、Oracle JVM Webサービス・コールアウト・ユーティリティで生成できます。
表A-1 有効なSQLデータ型-Javaクラス・マッピング
SQLデータ型 | Java型 |
---|---|
BOOLEAN |
boolean 、java.lang.Boolean 、oracle.sql.BOOLEAN |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
REF CURSOR |
j |
ユーザー定義の名前付き型、抽象データ型 |
|
opaque名前付き型 |
|
NESTED TABLEおよび |
|
名前付き型の参照 |
|
ノート:
-
UROWID
型はサポートされていません。 -
oracle.sql.Datum
は抽象クラスです。oracle.sql.Datum
型のパラメータに渡す値は、基礎となるSQL型に対応するJava型にする必要があります。同様に、戻り型oracle.sql.Datum
のメソッドから戻される値は、基礎となるSQL型に対応するJava型にする必要があります。
A.2 サポートされているSQLおよびPL/SQLデータ型
この項の表は、SQLとPL/SQLのデータ型、およびこれらのデータ型のOracle JDBCドライバのサポート状況のリストです。次の表は、SQLデータ型に対するOracle JDBCドライバのサポート状況のリストです。
表A-2 SQLデータ型に対するサポート
SQLデータ型 | JDBCドライバによるサポート |
---|---|
BFILE |
可 |
BLOB |
可 |
CHAR |
可 |
CLOB |
可 |
DATE |
可 |
NCHAR |
不可脚注1 |
NCHAR VARYING |
不可 |
NUMBER |
可 |
NVARCHAR2 |
可脚注2 |
RAW |
可 |
REF |
可 |
ROWID |
可 |
UROWID |
不可 |
VARCHAR2 |
可 |
脚注1
NCHAR型が間接的にサポートされています。対応するjava.sql.Types型はありませんが、アプリケーションがformOfUse(NCHAR)メソッドをコールする場合には、これらの型にアクセスできます。
脚注2
JSE 6では、NVARCHAR2型が間接的にサポートされています。J2SE 5.0では、NVARCHAR2型が間接的にサポートされています。対応するjava.sql.Types型はありませんが、アプリケーションがformOfUse(NCHAR)メソッドをコールする場合には、これらの型にアクセスできます。
次の表は、ANSIでサポートされているSQLデータ型に対するOracle JDBCドライバのサポート状況のリストです。
表A-3 ANSI-92 SQLデータ型に対するサポート
ANSIでサポートされているSQLデータ型 | JDBCドライバによるサポート |
---|---|
CHARACTER |
可 |
DEC |
可 |
DECIMAL |
可 |
DOUBLE PRECISION |
可 |
FLOAT |
可 |
INT |
可 |
INTEGER |
可 |
NATIONAL CHARACTER |
不可 |
NATIONAL CHARACTER VARYING |
不可 |
NATIONAL CHAR |
可 |
NATIONAL CHAR VARYING |
不可 |
NCHAR |
可 |
NCHAR VARYING |
不可 |
NUMERIC |
可 |
REAL |
可 |
SMALLINT |
可 |
VARCHAR |
可 |
次の表は、SQLユーザー定義型に対するOracle JDBCドライバのサポート状況のリストです。
表A-4 SQLユーザー定義型に対するサポート
SQLユーザー定義型 | JDBCドライバによるサポート |
---|---|
OPAQUE |
可 |
参照型 |
可 |
オブジェクト型( |
可 |
NESTED TABLE型およびVARRAY型 |
可 |
次の表は、PL/SQLデータ型に対するOracle JDBCドライバのサポート状況のリストです。PL/SQLデータ型には、次のカテゴリが含まれます。
-
スカラー型
-
スカラー文字列型(
DATE
データ型を含みます。) -
コンポジット型
-
参照型
-
ラージ・オブジェクト(LOB)型
表A-5 PL/SQLデータ型に対するサポート
PL/SQLデータ型 | JDBCドライバによるサポート |
---|---|
スカラー型: |
|
BINARY INTEGER |
可 |
DEC |
可 |
DECIMAL |
可 |
DOUBLE PRECISION |
可 |
FLOAT |
可 |
INT |
可 |
INTEGER |
可 |
NATURAL |
可 |
NATURALn |
不可 |
NUMBER |
可 |
NUMERIC |
可 |
PLS_INTEGER |
可 |
POSITIVE |
可 |
POSITIVEn |
不可 |
REAL |
可 |
SIGNTYPE |
可 |
SMALLINT |
可 |
BOOLEAN |
可 |
スカラー文字列型 |
|
CHAR |
可 |
CHARACTER |
可 |
LONG |
可 |
LONG RAW |
可 |
NCHAR |
不可(「ノート」を参照) |
NVARCHAR2 |
不可(「ノート」を参照) |
RAW |
可 |
ROWID |
可 |
STRING |
可 |
UROWID |
不可 |
VARCHAR |
可 |
VARCHAR2 |
可 |
DATE |
可 |
コンポジット型 |
|
RECORD |
不可 |
TABLE |
不可 |
VARRAY |
可 |
参照型: |
|
REF CURSOR型 |
可 |
オブジェクト参照型 |
可 |
LOB型: |
|
BFILE |
可 |
BLOB |
可 |
CLOB |
可 |
NCLOB |
可 |
ノート:
-
NATURAL
、NATURAL
n
、POSITIVE
、POSITIVE
n
およびSIGNTYPE
型は、BINARY INTEGER
のサブタイプです。 -
DEC
、DECIMAL
、DOUBLE PRECISION
、FLOAT
、INT
、INTEGER
、NUMERIC
、REAL
およびSMALLINT
型は、NUMBER
のサブタイプです。 -
NCHAR
型およびNVARCHAR2
型は間接的にサポートされています。対応するjava.sql.Types
型はありませんが、アプリケーションがformOfUse(NCHAR)
をコールする場合には、これらの型にアクセスできます。
A.3 PL/SQLタイプの使用について
Oracle Database 12cリリース1 (12.1)以降、スキーマ・レベルのPL/SQLタイプを汎用のjava.sql.Struct
タイプとして、PL/SQLコレクションをjava.sql.Array
タイプとしてマップできます。そのため、バインディング用にPL/SQLパッケージ・タイプにマップされるスキーマ・レベルのタイプを作成するかわりに、JDBC APIのみを使用して、PL/SQLタイプの記述およびバインドを行うことができます。
たとえば、Connection.createStruct(type_name)
メソッドをコールして、まずPL/SQLタイプの記述に使用できる記述子を作成し、次にクライアントでこのタイプの新しいSTRUCT
表現を作成することができます。Oracle Database 12c リリース1 (12.1)以降、type_name
を"schema.package.typename"
または"package.typename"
として指定して、このAPIを再利用できます。
PL/SQLパッケージ・タイプはすべて、システム全体で一意の名前にマップされます。この名前は、サーバー側のタイプ・メタデータを取得するためにJDBCで使用できます。名前の形式は次のとおりです。
[SCHEMA.]<PACKAGE>.<TYPE>
ノート:
スキーマがパッケージ名と同じ場合、また、PL/SQLタイプと同じ名前のタイプがある場合、2つのパート名の形式(<package>.<type>)のオブジェクトを識別できません。このような場合、3つのパート名(<schema>.<package>.<type>)を使用する必要があります。次のコードでは、PL/SQLパッケージで宣言されたタイプをバインドする方法を説明します。
/* --------------------------- # Perform the following SQL operations prior to running this sample --------------------------- conn HR/<password>; create or replace package TEST_PKG is type V_TYP is varray(10) of varchar2(200); type R_TYP is record(c1 pls_integer, c2 varchar2(100)); procedure VARR_PROC(p1 in V_TYP, p2 OUT V_TYP); procedure REC_PROC(p1 in R_TYP, p2 OUT R_TYP); end; / create or replace package body TEST_PKG is procedure VARR_PROC(p1 in V_TYP, p2 OUT V_TYP) is begin p2 := p1; end; procedure REC_PROC(p1 in R_TYP, p2 OUT R_TYP) is begin p2 := p1; end; end; / */ import java.sql.Array; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.SQLException; import java.sql.Struct; import java.sql.Types; import oracle.jdbc.OracleConnection; public class PLSQLTypesSample { public static void main(String[] args) throws SQLException { System.out.println("begin..."); Connection conn = null; oracle.jdbc.pool.OracleDataSource ods = new oracle.jdbc.pool.OracleDataSource(); ods.setURL("jdbc:oracle:oci:localhost:5521:orcl"); ods.setUser("HR"); ods.setPassword("hr"); //get connection conn = ods.getConnection(); //call procedure TEST_PKG.VARR_PROC CallableStatement cstmt = null; try { cstmt = conn.prepareCall("{ call TEST_PKG.VARR_PROC(?,?) }"); //PLSQL VARRAY type binding Array arr = ((OracleConnection)conn).createArray("TEST_PKG.V_TYP", new String[]{"A", "B"}); cstmt.setArray(1, arr); cstmt.registerOutParameter(2, Types.ARRAY, "TEST_PKG.V_TYP"); cstmt.execute(); //get PLSQL VARRAY type out parameter value Array outArr = cstmt.getArray(2); //... } catch( Exception e) { e.printStackTrace(); }finally { if (cstmt != null) cstmt.close(); } //call procedure TEST_PKG.REC_PROC try { cstmt = conn.prepareCall("{ call TEST_PKG.REC_PROC(?,?) }"); //PLSQL RECORD type binding Struct struct = conn.createStruct("TEST_PKG.R_TYP", new Object[]{12345, "B"}); cstmt.setObject(1, struct); cstmt.registerOutParameter(2, Types.STRUCT, "TEST_PKG.R_TYP"); cstmt.execute(); //get PLSQL RECORD type out parameter value Struct outStruct = (Struct)cstmt.getObject(2); //... } catch( Exception e) { e.printStackTrace(); }finally { if (cstmt != null) cstmt.close(); } if (conn != null) conn.close(); System.out.println("done!"); } }
%ROWTYPE属性を使用する各行のJavaレベルのオブジェクトの作成方法
%ROWTYPE
属性を使用して、Javaレベルのオブジェクトを作成できます。この場合、表の各行はjava.sql.Struct
オブジェクトとして作成されます。たとえば、パッケージpack1
では、次のように指定します。
CREATE OR REPLACE PACKAGE PACK1 AS TYPE EMPLOYEE_ROWTYPE_ARRAY IS TABLE OF EMPLOYEES%ROWTYPE; END PACK1; /
次のコードの抜粋に、JDBC APIを使用してEMPLOYEE_ROWTYPE_ARRAY
配列の値を取得する方法を示します。
この例では、java.sql.Struct
オブジェクトのjava.sql.Array
を戻します。そのStruct
要素はそれぞれEMPLOYEES
表の1行を表します。
例A-1 データベース表の行のためのSTRUCTオブジェクトの作成
CallableStatement cstmt = conn.prepareCall("BEGIN SELECT * BULK COLLECT INTO :1 FROM EMPLOYEE; END;"); cstmt.registerOutParameter(1,OracleTypes.ARRAY, "PACK1.EMPLOYEE_ROWTYPE_ARRAY"); cstmt.execute(); Array a = cstmt.getArray(1);
A.4 埋込みJDBCエスケープ構文の使用
Oracle JDBCドライバは、いくつかの埋込みJDBCエスケープ構文(中カッコで囲んで指定する構文)をサポートしています。現在のサポートは初歩的なものです。
ノート:
JDBCエスケープ構文は、以前はSQL92構文またはSQL92エスケープ構文と呼ばれていました。
この項では、ドライバによって提供される次の構文のサポートについて説明します。
ドライバのサポートが制限されている場合、これらの項では、選択可能な回避策についても説明します。
エスケープ処理の無効化
A.4.1 時刻および日付リテラル
A.4.1.1 日付リテラル
JDBCドライバは、次の形式で記述されたSQL文内の日付リテラルをサポートしています。
{d 'yyyy-mm-dd'}
yyyy-mm-dd
は、年、月および日を表します。たとえば:
{d '1995-10-22'}
JDBCドライバは、このエスケープ句を等価のOracleの表現「22 OCT 1995」に置換します。
次のコードの抜粋には、SQL文内での日付リテラルの使用例が含まれています。
// Connect to the database // You can put a database name after the @ sign in the connection URL. OracleDataSource ods = new OracleDataSource(); ods.setURL("jdbc:oracle:oci:@"); ods.setUser("HR"); ods.setPassword("hr"); Connection conn = ods.getConnection(); // Create a Statement Statement stmt = conn.createStatement (); // Select the first name column from the employees table where the hire date is Jan-23-1982 ResultSet rset = stmt.executeQuery ("SELECT first_name FROM employees WHERE hire_date = {d '1982-01-23'}"); // Iterate through the result and print the employee names while (rset.next ()) System.out.println (rset.getString (1));
A.4.1.2 時刻リテラル
JDBCドライバは、次の形式で記述されたSQL文内の時刻リテラルをサポートしています。
{t 'hh:mm:ss'}
hh:mm:ss
は、時、分および秒を表します。たとえば:
{t '05:10:45'}
JDBCドライバは、このエスケープ句を等価のOracleの表現「05:10:45」に置換します。
次のように時刻が指定されているとします。
{t '14:20:50'}
サーバーが24時間制のクロックを使用しているとすれば、等価のOracleの表現は「14:20:50」になります。
次のコードの抜粋には、SQL文内での時刻リテラルの使用例が含まれています。
ResultSet rset = stmt.executeQuery ("SELECT first_name FROM employees WHERE hire_date = {t '12:00:00'}");
A.4.1.3 タイムスタンプ・リテラル
JDBCドライバは、次の形式で記述されたSQL文内のタイムスタンプ・リテラルをサポートしています。
{ts 'yyyy-mm-dd hh:mm:ss.f...'}
yyyy-mm-dd hh:mm:ss.f...
は、年、月、日、時、分および秒を表します。端数秒の部分(.f...
)は省略できます。たとえば、{ts '1997-11-01 13:22:45'}
は、Oracle形式ではNOV 01 1997 13:22:45と表されます。
次のコードの抜粋には、SQL文内でのタイムスタンプ・リテラルの使用例が含まれています。
ResultSet rset = stmt.executeQuery ("SELECT first_name FROM employees WHERE hire_date = {ts '1982-01-23 12:00:00'}");
Oracleオブジェクト型からSQL DATEデータ型へのマッピング
Oracle Database 8iおよびそれ以前のリリースではTIMESTAMP
データはサポートされませんでしたが、Oracle DATE
データには、SQL標準を拡張するtimeコンポーネントがありました。このため、JDBCドライバのOracle Database 8iおよびそれ以前のリリースは、oracle.sql.DATE
をjava.sql.Timestamp
にマップしてtimeコンポーネントを維持していました。Oracle Database 9.0.1で初めてTIMESTAMP
のサポートが含まれ、9i JDBCドライバがoracle.sql.DATE
をjava.sql.Date
にマップするようになりました。このマッピングは不正確で、Oracle DATE
データのtimeコンポーネントを切り詰めました。この問題を解決するために、Oracle Database 11gリリース1では、新しいフラグmapDateToTimestamp
が導入されました。このフラグのデフォルト値はtrue
で、これは、ドライバがoracle.sql.DATE
をデフォルトでjava.sql.Timestamp
に正しくマップすることを意味します。不正確でも10gとの互換性があるoracle.sql.DATE
からjava.sql.Date
へのマッピングを使用する場合は、mapDateToTimestamp
フラグの値をfalse
に設定します。
ノート:
-
Oracle Database 11g以降、SQL問合せが使用するための索引がDATE列上にある場合、高速で正確な結果を入手するには、次のように
setObject
メソッドを使用する必要があります。Date d = parseIsoDate(val); Timestamp t = new Timestamp(d.getTime()); stmt.setObject(pos, new oracle.sql.DATE(t, (Calendar)UTC_CAL.clone()));
これは、
setDate
メソッドを使用する場合はOracle DATEデータのtimeコンポーネントが失われ、setTimestamp
メソッドを使用する場合はDATE列上の索引が使用されないためです。 -
oracle.sql.DATE
からjava.sql.Date
へのマッピングの問題を解決するために、Oracle Database 9.2でフラグV8Compatible
が導入されました。このフラグのデフォルト値はfalse
で、これによりjava.sql.Date
データへのOracleDATE
データのマッピングが可能になっています。ユーザーは、このフラグの値をtrue
に設定することによって、OracleDATE
データのtimeコンポーネントを維持できていました。このフラグは11g以降はサポートされなくなりました。それにより制御されるOracle Database 8iとの互換性がもうサポートされないためです。
A.4.2 スカラー関数
Oracle JDBCドライバでサポートしていないスカラー関数もあります。ドライバがサポートする関数を調べるには、Oracle固有のoracle.jdbc.OracleDatabaseMetaData
クラスおよび標準Javaのjava.sql.DatabaseMetadata
インタフェースでサポートされている次のメソッドを使用します。
-
getNumericFunctions()
ドライバによってサポートされている数値演算関数をカンマで区切られたリストで戻します。たとえば、「
ABS
,COS
,SQRT
」です。 -
getStringFunctions()
ドライバによってサポートされている文字列関数をカンマで区切られたリストで戻します。たとえば、「
ASCII
,LOCATE
」です。 -
getSystemFunctions()
ドライバによってサポートされているシステム関数をカンマで区切られたリストで戻します。たとえば、「
DATABASE
,USER
」です。 -
getTimeDateFunctions()
ドライバによってサポートされている時刻および日付関数をカンマで区切られたリストで戻します。たとえば、「
CURDATE
,DAYOFYEAR
,HOUR
」です。ノート:
Oracle JDBCドライバは、ファンクション・キーワードの
fn
をサポートしています。
A.4.3 LIKEエスケープ文字
SQL LIKE
句では、文字%
および_
には特別な意味があります。%
は0文字以上の一致、_
は1文字のみの一致に使用します。これらの文字を文字列内で文字どおりに使用する場合は、その前に特別なエスケープ文字を置きます。たとえば、アンパサンド&
をエスケープ文字として使用する場合は、SQL文内では次のように識別させます。
Statement stmt = conn.createStatement (); // Select the empno column from the emp table where the ename starts with '_' ResultSet rset = stmt.executeQuery ("SELECT empno FROM emp WHERE ename LIKE '&_%' {ESCAPE '&'}"); // Iterate through the result and print the employee numbers while (rset.next ()) System.out.println (rset.getString (1));
ノート:
円記号(\)をエスケープ文字として使用する場合は、2回入力する(\\とする)必要があります。たとえば:
ResultSet rset = stmt.executeQuery("SELECT empno FROM emp
WHERE ename LIKE '\\_%' {escape '\\'}");
A.4.4 MATCH_RECOGNIZE句
?
の文字は、Oracle Database 11g以上のバージョンでMATCH_RECOGNIZE
句でのトークンとして使用されます。JDBC標準が?
文字をパラメータ・マーカーとして定義するため、JDBCドライバおよびServer SQLエンジンは同じトークンの異なる使用を区別できません。
旧バージョンのJDBCドライバでは、?
文字をパラメータ・マーカーではなくMATCH_RECOGNIZE
トークンとして変換する場合、PreparedStatement
のかわりにStatement
を使用してエスケープ処理を無効にする必要があります。ただし、Oracle Database 12cリリース1 (12.1.0.2)以降からは、?
文字を使用すると同時に'{\\ ... \\}'
構文を使用することで、JDBCドライバでパラメータ・マーカーとして処理されることなく、SQLエンジンで処理できます。次のコード・スニペットは、'{\\ ... \\}'
構文の使用方法を示しています。
String sql = "select T.firstW, T.lastZ, ? " + // use of parameter marker "from tkpattern_S11 " + "MATCH_RECOGNIZE ( " + " MEASURES A.c1 as firstW, last(Z.c1) as lastZ " + " ALL MATCHES " + " {\\ PATTERN(A? X*? Y+? Z??)\\} " + // use of escape sequence " DEFINE " + " X as X.c2 > prev(X.c2), " + " Y as Y.c2 < prev(Y.c2), " + " Z as Z.c2 > prev(Z.c2)" + ") as T"; PreparedStatement ps = conn.prepareStatatement(sql); ps.setString(1, "test"); ResultSet rs = ps.executeQuery();
関連トピック
A.4.5 外部結合
OracleのJDBCドライバは、外部結合構文をサポートしていません。回避策は、Oracle外部結合構文を使用することです。
次の構文のかわりに、
Statement stmt = conn.createStatement (); ResultSet rset = stmt.executeQuery ("SELECT ename, dname FROM {OJ dept LEFT OUTER JOIN emp ON dept.deptno = emp.deptno} ORDER BY ename");
Oracle SQL構文を使用します。
Statement stmt = conn.createStatement (); ResultSet rset = stmt.executeQuery ("SELECT ename, dname FROM emp b, dept a WHERE a.deptno = b.deptno(+) ORDER BY ename");
A.4.7 JDBCエスケープ構文からOracle SQL構文変換例
JDBCエスケープ構文をOracle SQL構文に変換する簡単なプログラムを記述できます。次のプログラムは、ファンクション・コール、日付リテラル、時刻リテラルおよびタイムスタンプ・リテラルのためのJDBCエスケープ構文を使用する文に対して、それに対応するOracle SQL構文を出力します。このプログラムでは、oracle.jdbc.OracleSql
クラスのparse()
メソッドで変換します。
public class Foo { static oracle.jdbc.OracleDriver driver = new oracle.jdbc.OracleDriver(); public static void main (String args[]) throws Exception { show ("{call foo(?, ?)}"); show ("{? = call bar (?, ?)}"); show ("{d '1998-10-22'}"); show ("{t '16:22:34'}"); show ("{ts '1998-10-22 16:22:34'}"); } public static void show (String s) throws Exception { System.out.println (s + " => " + driver.processSqlEscapes(s)); } }
対応するSQL構文の出力です。
{call foo(?, ?)} => BEGIN foo(:1, :2); END; {? = call bar (?, ?)} => BEGIN :1 := bar (:2, :3); END; {d '1998-10-22'} => TO_DATE ('1998-10-22', 'YYYY-MM-DD') {t '16:22:34'} => TO_DATE ('16:22:34', 'HH24:MI:SS') {ts '1998-10-22 16:22:34'} => TO_TIMESTAMP ('1998-10-22 16:22:34', 'YYYY-MM-DD HH24:MI:SS.FF')
A.5 Oracle JDBCのノートおよび制限事項
A.5.6 DDL文の実行
Data Definition Language (DDL)文は、Statement
オブジェクトとともに実行する必要があります。PreparedStatements
オブジェクトまたはCallableStatements
オブジェクトを使用する場合、DDL文は初回の実行時にのみ有効です。SQL文が文キャッシュ内にある場合、これにより予期しない動作になる可能性があります。
A.5.7 名前付きパラメータのバインド
set
XXX
メソッドを使用する場合、名前によるバインドはサポートされていません。特定の環境下では、以前のバージョンのOracle JDBCドライバは、set
XXX
メソッドの使用時にも名前によって文変数をバインドできました。次の文では、名前付き変数EmpId
が整数314159
とバインドされます。
PreparedStatement p = conn.prepareStatement ("SELECT name FROM emp WHERE id = :EmpId"); p.setInt(1, 314159);
set
XXX
メソッドを使用して名前を基準にバインドするこの機能は、JDBC仕様には含まれず、Oracleではサポートされません。JDBCドライバは、SQLException
をスローしたり、予想外の結果になったりすることがあります。Oracle Database 10g のJDBCドライバ以降、名前を基準としたバインドはset
XXX
AtName
メソッドを使用してサポートされています。
execute
メソッドをコールするまで、ドライバはバインド値をコピーしません。このためexecute
メソッドをコールする前にバインド値を変更すると、バインド値が変更されることがあります。たとえば、次のコードを考えてみましょう。
PreparedStatement p; ....... Date d = new Date(1181676033917L); p.setDate(1, d); d.setTime(0); p.executeUpdate();
このコードはデータベースにDate(1181676033917L)
でなくDate(0)
を挿入します。これは、パフォーマンス上の理由でJDBCドライバ実装によりバインド値がコピーされていないためです。