今回もそんなシステムでした。

begin Insert into blob_tab (blob_col) values (? サンプル2:OCI DB(DBaaS)のCDBにsqlclでJDBC URLを指定しつつ接続, 6. )}"); CallableStatement cs2 = conn.prepareCall ("{? https://www.oracle.com/technetwork/jp/articles/chapter5-1-101584-ja.html#p01b, リスナーは1組以上のホスト名(IPアドレス)/ポート番号が定義されていて、 . ResultSet rset = stmt.executeQuery ("select ROWID from EMP"); ... rset.close (); // or stmt.close (); rset.getString (1); 元のJDBC仕様では、Connection、Statement、およびResultSetにアクセスできなくなったときにはクローズする必要があります。この場合には、ファイナライザを使用する必要があります。ただしファイナライザを使用すると、すべてのファイナライザが置かれているJVMで実行されているアプリケーションのすべての側面に関して、パフォーマンスが大幅に低下します。Sunでは、ファイナライザを使用しないことを推奨しています。自動クローズではファイナライザを使用する必要がありますが、これにより自動クローズを利用しているかどうかに関係なく、すべてのユーザーに対して悪影響を与えてしまいます。これは許容されるトレードオフではありません。, 考えられる限りにおいては、上の説明に厳密に一致する理由により、ベンダーのJDBCドライバに自動クローズは実装されていませんし、これまで実装されていたこともありません。この要件は仕様から削除されていますが、何箇所かこの表現が残っている場合があります。JDBCチュートリアルの場合も同様です。このチュートリアルは参考になり便利ですが、正式なドキュメントではありません。何年間も更新されていません。JDBC 4.0仕様では、自動クローズは一切必要ありません。, ResultSet、Statemnent、およびConnectionのすべてにおいて、クライアント側とサーバー側の両方のリソースが採用されます。これらのオブジェクトがオープンされている限り、関連するリソースが割り当てられます。このリソースが解放されるのは、オブジェクトがクローズされたときのみです。ResultSet、Statement、およびConnectionのクローズに失敗するとリソース・リークが発生し、アプリケーションのパフォーマンスに影響が出ます。, Connectionをクローズすると、関連するすべてのStatementがクローズされます。Statementをクローズすると、関連するすべてのResultSetがクローズされます。このため、Connectionを終了する場合は、ConnectionをクローズするだけですべてのStatementとResultSetがクローズされます。これは許容できるプログラミング手法です。さらに適切な手法は、最終ブロックでStatementとResultSetを明示的にクローズすることです。こうすることにより、アプリケーションが要件の変更に適合するように修正された際に堅牢度が増し、リソース・リークが発生する可能性も低くなります。, PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(sql); try { rs = ps.executeQuery(); while (rs.next()) { // process row } } finally { if (rs != null) rs.close(); } } finally { if (ps != null) ps.close(); }, Oracle JDBCドライバの9.2以前では、DATE SQLデータ型がjava.sql.Timestampにマッピングされていました。Oracle DATE SQLデータ型には、java.sql.Timestampの場合と同様に日付と時刻の両方の情報が含まれているため、この処理にはある一定の意味がありました。java.sql.Dateには時刻情報が含まれていないため、java.sql.Dateに明確なマッピングを行うことには多少の問題がありました。また、RDBMSではTIMESTAMP SQLデータ型がサポートされていなかったため、DATEをTimestampにマッピングすることに関して問題はありませんでした。, 9.2では、RDBMSにTIMESTAMPのサポートが追加されました。DATEとTIMESTAMPの違いは、TIMESTAMPにはナノ秒が含まれていますが、DATEには含まれていないということです。このため9.2以降では、DATEがDateに、TIMESTAMPがTimestampにマッピングされています。ただし、時刻情報を含めるためにDATE値を利用していた場合は、問題が発生します。, 9.2以降10.2までのドライバでは、この問題に対処するために次のいくつかの方法が用意されています。, Oracle JDBC 11.1では、この問題は修正されています。このリリース以降のドライバでは、デフォルトでSQL DATE列がjava.sql.Timestampにマッピングされています。正しいマッピングを取得するために、V8Compatibleを設定する必要はありません。V8Compatibleは非推奨です。一切使用しないでください。trueに設定しても問題はありませんが、使用しないことを推奨します。, V8Compatibleはまれに使用されていたこともありますが、DATEからDateへの変更に関する問題を修正するためではなく、8iデータベースとの互換性をサポートするために存在していました。8i(およびそれ以前の)データベースでは、TIMESTAMP型はサポートされていませんでした。V8Compatibleを設定すると、データベースからの読取り時にSQL DATEがTimestampにマッピングされるだけでなく、データベースへの書込み時にTimestampがSQL DATEに変換されてしまいます。8iのサポートは終了しているため、11.1 JDBCドライバではこの互換性モードはサポートされていません。このため、V8Compatibleのサポートは終了しています。, 上で説明したように、11.1ドライバではデフォルトで、データベースからの読取り時にSQL DATEがTimestampに変換されます。これは常に正しい処理でしたが、9iでの変更時に誤りが発生していました。11.1ドライバでは正しい動作に戻されています。アプリケーションでV8Compatibleを設定していない場合でも、たいていの場合動作に違いはありません。getObjectを使用してDATE列を読み取る際に、違いに気付く可能性があります。結果は、DateではなくTimestampになります。TimestampはDateのサブクラスであるため、通常この点は問題にはなりません。違いに気付く可能性があるのは、DATEからDateへの変換を利用して時刻部分を切り捨てる場合か、または値に対してtoStringを実行する場合です。それ以外の場合は、変更は透過的になるはずです。, 何らかの理由により、この変更に対してアプリケーションが大きな影響を受け、9i以降10gまでの動作を指定する必要がある場合、設定可能なConnectionプロパティが存在します。mapDateToTimestampをfalseに設定すると、ドライバの動作がデフォルトの9i以降10gまでの動作に戻され、DATEがDateにマッピングされます。, 9.2では、LONGのsetString()により、OCIドライバでは最大64000文字、シン・ドライバでは最大4000文字を挿入できます。10.1.0では、両方のドライバの制限値が32000文字に変更されています。OCIの制限値を64000から32000に減少させたことにより、一部のお客様で問題が発生する可能性があることは認識しています。ただし、この変更により達成可能な大幅なパフォーマンス向上について検討し、アーキテクチャの変更が必要であると判断した結果、オラクルではお客様に対してLONGからCLOBに移行することを強く推奨します。, 32000を超える文字を処理するためにsetString()が必要になるお客様に対して、LONGからCLOBに移行することを推奨します。, 以前の動作は、データベース値と同じ値を出力するTimestampを構成することでした。しかし、TimestampのタイムゾーンがUTCであるため、正しい値からオフセット量のあるTimestamp値が出力されていました。UTCにおける2007年1月1日午前8時は、PSTにおける2007年1月1日午前8時と同じではありません。これらは、別の時刻ポイントを表しています。, データベースでの読取り時刻がPSTにおける2007年1月1日午前8時の場合、9iおよび10gドライバではUTCにおける2007年1月1日午前8時という値でTimestampが構成されています。この値は、"2007年1月1日午前8時"と"正しく"出力されていますが、明らかに誤った時刻ポイントを表しています。11.1ドライバではこのバグは修正されています。, JDBC 4.0では、ADTインスタンスの作成用としてConnectionインタフェースに関するファクトリ・メソッドが導入されました。このメソッドはコンストラクタを使用する場合と比較して、非常に適したAPIです。可能な限り、ファクトリ・メソッドを使用することを強く推奨します。コンストラクタの使用はできるだけ早い時期に非推奨にし、可能な限り早急にサポートを終了する予定です。, 標準のファクトリ・メソッドが導入されたのはJDBC 4.0であるため、このメソッドが使用できるのはJSE 6ドライバ(ojdbc6.jar)のみです。オラクル独自の型を作成するために、JSE 5とJSE 6(ojdbc5.jarとojdbc6.jar)の両方に対してOracleConnectionでファクトリ・メソッドが定義されています。もう一度繰り返しますが、ファクトリ・メソッドを使用することを強く推奨します。, SQL標準の配列型はanonymous(匿名)で、これは"array of foo(foo配列)"型には名前がないという意味です。名前が付けられているのは、要素型のみです。Oracle SQLでは、配列型に名前が付けられています。実際、匿名の配列型はサポートされていません。このため、JDBC 4.0の標準のファクトリ・メソッドでは引数として要素型を取得し、匿名配列型のインスタンスが作成されます。Oracle JDBCドライバでは、オラクル独自のメソッドcreateArrayが定義されています。このメソッドでは配列型の名前が取得され、その名前の付いた配列型のインスタンスが返されます。この処理は、Oracle SQLが定義される方法で必要になります。現時点では、Oracle DatabaseにおいてJDBC 4.0の標準createArrayOfメソッドをサポートすることはできません。, CLOBのセグメントを"消去"するだけです。CLOBの長さを短くは*しません*。このため、CLOBの長さは消去の前後で同じです。CLOBの長さを短くするには、DBMS_LOB.TRIMを使用します。, はい。使用できますが、位置と長さの引数が正しいことを確認する必要があります。また、推奨のOutputStreamインタフェースを使用して、次にputCharsをコールすることもできます。, JDBCではCLOBは*常に*USC2に置かれていますが、これはJava "char"型に対応するOracleキャラクタ・セットです。このため、OCI CLOB CharSetIdに同等なものは存在しません。, モデルによって異なります。10000よりも小さい値を書き込む場合は、LONG RAWの方が高速です。大きい値を書き込む場合は、違いがなくなります。, これが正しい動作です。LONG列はインプレース(別名インロー)では'フェッチ'されません。この列はアウトオブプレースでフェッチされ、明示的に読み取るまでパイプ内に置かれます。この場合はLobLocatorを取得(getBlob())し、LONG列を読み取る前にこのLOBの長さの取得を試みます。パイプは空でないため、上の例外が発生します。解決策は、BLOBで何らかの操作を実行する前に、LONG列の読取りを完了することです。, Oracle LOBでは、値セマンティクスが使用されています。LOBを更新する際には、LOBをデータベースに書き戻して変更内容を確認する必要があります。技術的な理由により、LOBを書き込んでいないときでも変更内容が保存される場合があります。ただし、この現象がいつ発生するのかは予測できないため、必ずLOBを書き込む必要があります。, 以前は可能でしたが、その後可能ではなくなりました。現在、REFはシリアライズ可能です。, REFがシリアライズ可能ではない、旧バージョンのOracle JDBCドライバを使用している場合、次の注意事項がまだ有効である可能性があります。, REFクラスの重要な構成要素はバイト配列であり、この配列はオブジェクト参照およびオブジェクト・タイプの完全修飾名を表しています。次の"SomeREF"クラスのような1つのクラスを使用して、オブジェクトREFのバイト数とタイプ名を保持できます。このクラスはシリアライズ可能です。また、パラメータとしてJDBC Connectionを必要とする"toREF"メソッドで、REFを再作成できます。, public class SomeREF implements java.io.Serializable { String typeName; byte[] bytes; public SomeREF (oracle.sql.REF ref) throws SQLException { this.typeName = ref.getBaseTypeName (); this.bytes = ref.getBytes (); } public oracle.sql.REF toREF (Connection conn) throws SQLException { return new oracle.sql.REF (new oracle.sql.StructDescriptor (typeName,conn),conn, bytes); } }, Oracle8オブジェクト・タイプへのREFを含む表に対して問合せを実行できます。また、このREFはJDBCにより、Java oracle.sql.REFオブジェクトとしてマテリアライズされます。JDBCでは、新しいREFを最初から作成することはできません。データベースに移動して、新しいREFをSQLに挿入する必要があります。その後、REFを選択してクライアントに返す必要があります。, この処理は、PL/SQLブロックで実行するのが簡単です。たとえば、次の表がある場合です。.