15 ラージ・オブジェクトおよびSecureFilesの使用
ラージ・オブジェクト(LOB) とは、大量のデータを保持するように設計されたデータ型のセットです。この章では、データ・インタフェースまたはロケータ・インタフェースのいずれかを使用して、LOBおよびSecureFilesにアクセスし、操作するために、Java Database Connectivity (JDBC)を使用する方法について説明します。
この章の構成は、次のとおりです。
15.1 LOBデータ型
Oracle Databaseでは、次の4つのLOBデータ型をサポートします。
-
バイナリ・ラージ・オブジェクト(BLOB)
このデータ型は、非構造バイナリ・データに使用されます。
-
キャラクタ・ラージ・オブジェクト(CLOB)
このデータ型は、文字データに使用されます。
-
各国語キャラクタ・ラージ・オブジェクト(NCLOB)
このデータ型は、各国語文字データに使用されます。
-
BFILE
このデータ型は、データベース表領域外の、オペレーティング・システム・ファイルに格納されるラージ・バイナリ・データ・オブジェクトに使用されます。
BLOB、CLOBおよびNCLOBは、データベース表に永続的に格納され、これらのデータ型に対する操作はすべて、トランザクション制御の下で実行されます。BLOB、CLOBまたはNCLOB型の一時LOBを作成して、一時データを保持することもできます。永続LOBと一時LOBはどちらも、データ・インタフェースおよびロケータ・インタフェースを使用してアクセスおよび操作できます。
BFILEは、Oracle独自のデータ型で、3次ストレージ・デバイス(ハード・ディスク、ネットワーク・マウント・ファイルシステム、CD-ROM、PhotoCDおよびDVDなど)上のデータベース表領域外にあるデータに読取り専用アクセスが可能です。BFILEデータは、トランザクション制御下にはなく、データベース・バックアップでは保存されません。
PL/SQL言語では、LOBデータ型がサポートされ、JDBCインタフェースにより、PL/SQLのプロシージャまたはファンクションへのINパラメータの引渡しや、OUTパラメータや戻り値の取出しが可能です。
15.2 永続LOB
永続LOBとは、データベースの表の行に存在するLOBインスタンスです。永続LOBは、SecureFilesまたはBasicFilesとして格納できます。
関連項目:
永続LOBSecureFilesは、データベース表でのLOBのデフォルトの記憶域メカニズムです。SecureFile LOBは、自動セグメント領域管理(ASSM)で管理される表領域でのみ作成できます。SecureFilesは、BLOB、CLOBおよびNCLOBの格納および管理にお薦めします。
Oracle SecureFilesの次の機能は、既存のAPIを介してJDBCプログラムで透過的に使用可能です。
- 圧縮により、データを圧縮してディスク容量を節約できます。
- 暗号化により、暗号化されたデータのランダムな読取りおよび書込み操作を可能にする暗号化機能が提供されます。
- 重複除外により、重複LOBデータが自動検出され、データを一部のみ保存することで容量が節約されます。
isSecureFileメソッド
BLOB
またはCLOB
データによってOracle SecureFile記憶域が使用されているかどうかをチェックできます。このチェックを行うには、oracle.jdbc.OracleBlob
クラスまたはoracle.jdbc.OracleClob
クラスの次のメソッドを使用します。
public boolean isSecureFile() throws SQLException
このメソッドからtrue
が戻された場合、データはSecureFile記憶域を使用しています。
永続LOBと一時LOBはどちらも、データ・インタフェースおよびロケータ・インタフェースを使用してアクセスおよび操作できます。
15.3 一時LOB
一時LOBは、一時データの格納に使用できます。一時LOBは、サイズに応じてPGAメモリーまたは一時表領域のいずれかに存在します。
通常のデータベース表に一時LOBを挿入できます。このような場合は、LOBの永続コピーが作成されて格納されます。
関連項目:
一時LOB一時LOBの作成
一時LOBは、oracle.sql.BLOB
クラスとoracle.sql.CLOB
クラスの両方で定義されているstatic createTemporary
メソッドで作成します。JDBC 4.0で利用できる接続ファクトリ・メソッドを使用することにより、一時LOBを作成することもできます。Oracle JDBCドライバにより、ファクトリ・メソッドcreateBlob
、createClob
およびcreateNClob
が、一時LOBを作成するためにjava.sql.Connection
インタフェースで実装されます。
一時LOBの解放
一時LOBを解放するには、freeTemporary
メソッドを使用します。isTemporary
メソッドをコールすることで、LOBが一時LOBかどうかをテストできます。LOBがcreateTemporary
メソッドをコールして作成された場合、isTemporary
メソッドは、true
を戻し、それ以外の場合はfalse
を戻します。
Oracle Databaseリリース21c以降では、一時LOBを解放する前に、LOBが一時LOBであるか永続LOBであるかを確認する必要はありません。LOBに対してDBMS_LOB.FREETEMPORARY
プロシージャまたはOCILobFreeTemporary()
ファンクションをコールすると、次のいずれかの操作が実行されます。
- 一時LOBの場合は、LOBを解放します。
- 永続LOBの場合は、何も実行されません(no-op)。
ノート:
- セッションまたはコールを終了する前に、一時LOBを解放する必要があります。一時LOBを解放しない場合は、データベース内でそのLOBによって使用されている記憶域を使用できないようにします。頻繁に一時LOBを解放しないと、一時表領域が使用できないLOB記憶域でいっぱいになってしまいます。
java.sql.Blob
、java.sql.Clob
およびjava.sql.NClob
インタフェースにあるJDBC 4.0のfree
メソッドは、freeTemporary
メソッドに優先します。
永続LOBと一時LOBはどちらも、データ・インタフェースおよびロケータ・インタフェースを使用してアクセスおよび操作できます。
15.4 LOBのデータ・インタフェース
LOB用のデータ・インタフェースには、LOBデータ型を処理するように拡張された一連のJava APIおよびOCI APIが組み込まれています。
このデータ・インタフェースでは、標準JDBCメソッド(getString
メソッドやsetBytes
メソッドなど)を使用して、LOBデータの読取りと書込みを行います。標準のjava.sql.Blob
、java.sql.Clob
およびjava.sql.NClob
インタフェースと異なり、このデータ・インタフェースにはランダム・アクセス機能はなく、LOBロケータを使用していないので、サイズが2 GBを超えるデータにはアクセスできません。
関連項目:
LOBのデータ・インタフェースLOB用のデータ・インタフェースを使用すると、対応するレガシー・データ型(VARCHAR2
、LONG
、RAW
など)に格納されている場合と同様に、文字データとバイナリ・データをLOB列に格納して操作できます。この節では、以下のトピックについて説明します。
15.4.1 入力
PreparedStatement
インタフェースのsetBytes
、setBinaryStream
、setString
、setCharacterStream
およびsetAsciiStream
メソッドは、BLOB
、CLOB
およびNCLOB
ターゲット列を処理する機能を強化するために拡張されています。データの長さが不明である場合は、パフォーマンスを向上させるために、データの長さをパラメータとして受け入れるsetBinaryStream
またはsetCharacterStream
メソッドのバージョンを使用します。
ノート:
これらのメソッドは、読取り専用のBFILE
データでは機能しません。
JDBC Oracle Call Interface (OCI)とThinドライバには、byte
配列やString
のサイズに制限はなく、ストリーム・ファンクションに指定された長さには、Java言語の制限を除けば、制限はありません。
ノート:
Javaでは、配列サイズは正のJavaint
または2 GBのサイズに制限されています。
サーバー側内部ドライバについては、現在INSERT
文などのSQL文の操作に32767バイトという制限があります。この制限はPL/SQL文には適用されません。LOBをPL/SQLブロックにラップできるINSERT
文では、次の回避方法を使用できます。
BEGIN INSERT id, c INTO clob_tab VALUES(?,?); END;
LOBの入力モード
LOBには、次の3つの入力モードがあります。
-
直接バインディング
このバインディングは、サイズに制限がありますが、最も効率的です。すべての入力列のデータを、サーバーに送信するデータのブロックにインラインで配置します。バッチの複数回実行を含め、すべてのデータは1回のネットワーク操作で送信されます。
-
ストリーム・バインディング
このバインディングでは、データが最後に配置されます。バッチ・サイズは1つに制限され、完了に複数回のラウンドトリップが必要になる場合があります。
-
LOBバインディング
このバインディングでは、一時LOBを作成し、データをLOBにコピーして、LOBロケータをバインドします。一時LOBは、実行後、自動的に解放されます。一時LOBを作成してから、LOBに書き込む操作には、複数回のラウンドトリップが必要です。ロケータの入力はバッチ処理されます。
LOBに対する次のような入力モードの自動切替えは留意する必要があります。
-
SQL文の場合
-
setBytes
およびsetBinaryStream
メソッドでは、32767バイト未満のデータには直接バインディングを使用します。 -
setBytes
およびsetBinaryStream
メソッドでは、32767バイトを超えるデータにはストリーム・バインディングを使用します。 -
JDBC 4.0以降は、2つの形式の
setAsciiStream
、setBinaryStream
およびsetCharacterStream
メソッドがあります。長さとしてlong
引数を取る形式では、2147483648を超える長さにはLOBバインディングを使用します。長さを指定しない形式では、常にLOBバインディングを使用します。 -
setString
、setCharacterStream
およびsetAsciiStream
メソッドでは、32767文字未満のデータには直接バインディングを使用します。 -
setString
、setCharacterStream
およびsetAsciiStream
メソッドでは、32766文字を超えるデータにはストリーム・バインディングを使用します。
-
-
PL/SQL文の場合
-
setBytes
およびsetBinaryStream
メソッドでは、32767バイト未満のデータには直接バインディングを使用します。 -
setBytes
およびsetBinaryStream
メソッドでは、32766バイトを超えるデータにはLOBバインディングを使用します。 -
setString
、setCharacterStream
およびsetAsciiStream
メソッドでは、データベース文字セットで32767バイト未満のデータには直接バインディングを使用します。 -
setString
、setCharacterStream
およびsetAsciiStream
メソッドでは、データベース文字セットで32766バイトを超えるデータにはLOBバインディングを使用します。
-
- LOBへの変換の強制
oracle.jdbc.OraclePreparedStatement
インタフェースにあるsetBytesForBlob
およびsetStringForClob
メソッドでは、すべてのデータ・サイズにLOBバインディングを使用します。
入力モードの自動切替えの影響
大量データの入力モードの自動切替えは、一部のプログラムに影響を与えます。以前は、32766文字を超えるString
値にsetString
メソッドを使用しようとすると、ORA-17157
エラーが発生していました。現在は、ターゲット・パラメータの型に応じて、文の実行中にエラーが発生する場合と、操作が成功する場合があります。
もう1つの影響は、自動切替えの結果、パラメータの型の変更に適合させるために追加のサーバー側解析が実行される場合があることです。その結果、文が繰り返し実行されてデータ・サイズが制限の上下に変動すると、パフォーマンスに影響が生じます。ストリーム・モードへの切替えはバッチ処理にも影響を与えます。
15.4.2 出力
ResultSet
およびCallableStatement
インタフェースのgetBytes
、getBinaryStream
、getString
、getCharacterStream
およびgetAsciiStream
メソッドは、BLOB
、CLOB
およびBFILE
の各列またはOUT
パラメータを処理できます。これらのメソッドは、2147483648未満の長さのすべてのLOB
に機能します。
ノート:
getString
メソッドとgetNString
メソッドを使用してBLOB列値を取得することはできません。
データ・インタフェースはドライバ内でのLOB
ロケータへのアクセスにより動作し、アプリケーション・プログラミング・インタフェースに対して透過的に行われます。
defineColumnType
メソッドを使用して、BFILE
データの読取り、およびBLOB
またはCLOB
データの読取りと書込みを行うことができます。読み取るには、列に対してdefineColumnType(nn,
Types.LONGVARBINARY)
またはdefineColumnType(nn,Types.LONGVARCHAR)
メソッドを使用します。これにより、データがLONG RAW
列またはLONG
列であるかのように直接ストリームが生成され、LOBでの読取りパフォーマンスが最も速くなります。
LOBのプリフェッチを使用して、追加のデータベース・ラウンドトリップを減らすかなくすこともできます。
15.4.3 CallableSatementとIN OUTパラメータ
ストアド・プロシージャのIN
OUT
CLOB
パラメータがあり、このパラメータの値を設定するためにsetString
メソッドを使用する場合、IN
およびOUT
パラメータに対してバインドは同じタイプである必要があります。
ノート:
PL/SQLの要件は、IN OUTパラメータの入力と出力に同じJava型を使用する必要があります。この章で説明した拡張機能による型の自動切替えが原因で、これに関して問題が発生する場合があります。 データ・サイズが判明していない場合は、入力モードの自動切替えによって問題が発生します。たとえば、入力データおよび出力データの両方が32766バイトを超えないことが判明している場合は、入力パラメータにsetString
メソッドを使用し、OUT
パラメータをTypes.VARCHAR
として登録し、出力パラメータにgetString
メソッドを使用できます。
よりよい解決方法は、ストアド・プロシージャを変更してIN
パラメータとOUT
パラメータを個別にすることです。つまり、アプリケーションに次のコードの抜粋があるとします。
CREATE PROCEDURE clob_proc( c IN OUT CLOB );
これを次のように変更します。
CREATE PROCEDURE clob_proc( c_in IN CLOB, c_out OUT CLOB );
もう1つの回避方法は、コンテナ・ブロックを使用してコールすることです。次のようにclob_proc
プロシージャをJava文字列でラップすると、prepareCall
文に使用できます。
"DECLARE c_temp; BEGIN c_temp := ?; clob_proc( c_temp); ? := c_temp; END;"
どちらの場合でも、最初のパラメータにsetString
メソッドを使用し、2番目のパラメータにregisterOutParameter
メソッドとTypes.CLOB
を使用できます。
15.5 LOBのロケータ・インタフェース
ロケータは少量データ構造体で、LOBの実際のデータへのアクセスに使用できる情報が格納されます。データベース表で、ロケータは表に直接格納されるのに対し、データはその表または別の記憶域に格納できます。
関連項目:
LOBのロケータ・インタフェースJDBC 4.0以降では、LOBに対する読取りおよび書込み操作を実行するために、java.sql.Blob
、java.sql.Clob
およびjava.sql.NClob
インタフェースを使用する必要があります。これらのインタフェースにより、LOBのデータにはランダム・アクセスできます。
Oracle実装クラスのoracle.sql.BLOB
、oracle.sql.CLOB
およびoracle.sql.NCLOB
ではロケータを格納し、それを使用してデータにアクセスします。oracle.sql.BLOB
クラスとoracle.sql.CLOB
クラスは、それぞれjava.sql.Blob
インタフェースとjava.sql.Clob
インタフェースを実装します。ojdbc6.jar
では、oracle.sql.NCLOB
はjava.sql.NClob
を実装しますが、ojdbc5.jar
では、java.sql.Clob
インタフェースを実装します。
ノート:
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.BLOB
クラスおよびoracle.sql.CLOB
クラスは非推奨となり、oracle.jdbc.OracleBlob
インタフェースおよびoracle.jdbc.OracleClob
インタフェースに置き換えられています。標準互換性には(可能であれば)java.sql
パッケージの使用可能なメソッドを使用し、Oracle固有の拡張機能にはoracle.jdbc
パッケージの使用可能なメソッドを使用することをお薦めします。これらのインタフェースの詳細は、MoSノート1364193.1を参照してください。
Oracle Database 23cでは、Oracle JDBCドライバは、JDK 11でコンパイルされるojdbc11.jar
のJDBC 4.0 java.sql.NClob
インタフェースをサポートします。
これに対し、oracle.sql.BFILE
はOracle拡張機能で、対応するjava.sql
インタフェースはありません。
関連項目:
JDBC Javadoc15.5.1 LOBプリフェッチ
現在のリリースのJDBCドライバの場合、通常のフェッチ操作中にロケータとともに、LOBの長さやチャンク・サイズなどのメタデータおよびLOBデータの始めをプリフェッチすることで、ラウンドトリップの回数を減らします。
LOB列を選択して結果セットに入れる場合、ロケータがフェッチされると、データの一部またはすべてをクライアントにプリフェッチできます。ロケータからフェッチするまで、前述の操作を保留することによって、最初のラウンドトリップを行わずにデータを取得します。
ノート:
- LOBは、STRUCTやARRAYなどの抽象データ型(ADT)ではプリフェッチされません。この動作は、
oracle.jdbc.defaultLobPrefetchSize
接続プロパティの値を設定した場合でも発生します。クライアント・アプリケーションが、このようなデータ型に埋め込まれているLOBの値に依存する操作を実行する場合、値をフェッチするには追加のラウンドトリップが必要です。 - プリフェッチの利点は、小さいLOBの方が多く、大きいLOBの方が少なくなることです。
- 大型LOBのプリフェッチ・サイズを、行プリフェッチ・サイズや多数のLOB列と一緒に設定するときには、予想されるメモリー消費に注意する必要があります。
デフォルトのプリフェッチ・サイズは32768です。プリフェッチ・サイズは、oracle.jdbc.defaultLobPrefetchSize
接続プロパティを使用して、BLOBの場合はバイト数、CLOBの場合は文字数で指定できます。このプロパティの値は、次の2つの方法でオーバーライドできます。
- 文レベル:
oracle.jdbc.OracleStatement.setLobPrefetchSize(int)
メソッドを使用 - 列レベル: 長さを引数として取る
defineColumnType
メソッドの形式を使用
関連項目:
JDBC Javadoc15.5.2 LOBのオープン操作とクローズ操作
この項では、LOBのオープンとクローズの方法について説明します。
この項では、LOBのオープンとクローズの方法について説明します。この機能は、oracle.sql.BLOB
およびoracle.sql.CLOB
インタフェースで使用可能な次のメソッドを使用して、JDBC実装されます。
void open (int mode)
void close()
boolean isOpen()
ノート:
LOBは必ずしもオープンおよびクローズする必要はありません。パフォーマンス上の理由から、オープンとクローズを選択できます。関連項目:
LOBのオープン操作とクローズ操作15.6 BFILE
BFILEは、データベース表領域の外にあるオペレーティング・システム・ファイルに格納されるデータ・オブジェクトです。BFILE型の表列に格納されたデータは、データベースではなくオペレーティング・システム・ファイルに物理的に置かれます。BFILE列には、オペレーティング・システム・ファイルへの参照が格納されます。
BFILEは読取り専用です。データの本体はオペレーティング・システム(OS)のファイル・システムにあり、OSのツールとコマンドを使用しないとBFILEに書き込めません。JDBC API、またはSQLを実行する別の方法を使用して、適切なSQL文を実行することにより、既存の外部ファイル用のBFILEを作成できます。ただし、SQLまたはJDBCを使用すると、BFILEが参照するOSファイルを作成できません。このようなOSファイルは、サーバー・ファイル・システムにアクセスできる外部プロセスによってのみ作成されます。
関連項目:
BFILEこの項では、ファイル・ロケータを使用してBFILEの読取りおよび書込み操作を実行する方法について説明します。この項の内容は次のとおりです。
BFILEロケータの取出し
BFILEを操作するBFILEデータ型とoracle.jdbc.OracleBfile
インタフェースは、どちらもOracle独自のものです。したがって、これらには標準インタフェースはありません。この型のデータには、Oracle拡張機能を使用する必要があります。
標準JDBC結果セットまたはBFILEロケータを含むコール可能文オブジェクトがある場合は、標準結果セットのgetObject
メソッドを使用して、ロケータにアクセスできます。このメソッドは、oracle.jdbc.OracleBfile
オブジェクトを戻します。
また、結果セットをOracleResultSet
にキャストするか、コール可能文をOracleCallableStatement
にキャストし、getOracleObject
またはgetBFILE
メソッドを使用することにより、ロケータにアクセスすることもできます。
ノート:
getObject
またはgetOracleObject
メソッドを使用している場合は、必要に応じて出力をキャストしてください。
ロケータがある場合は、oracle.jdbc.OracleBfile
クラスに存在するAPIを介してBFILEデータにアクセスできます。これらのAPIは、oracle.jdbc.OracleBfile
インタフェースの読取りメソッドに似ています。
BFILEの挿入
oracle.jdbc.OracleBfile
インタフェースのインスタンスは、SQL文またはPL/SQLプロシージャへの入力として使用できます。これは次のいずれかを実行することで行えます。
- 標準の
setObject
メソッドを使用します。 - 文を
OraclePreparedStatement
またはOracleCallableStatement
にキャストし、setOracleObject
またはsetBFILE
メソッドを使用します。これらのメソッドは、パラメータ索引およびoracle.jdbc.OracleBfile
オブジェクトを入力として取ります。ノート:
-
BFILE用の標準
java.sql
インタフェースはありません。 -
getBFILE
メソッドをOracleResultSet
およびOracleCallableStatement
インタフェースで使用して、oracle.jdbc.OracleBfile
オブジェクトを取り出します。OraclePreparedStatement
およびOracleCallableStatement
インタフェースのsetBFILE
メソッドは、引数としてoracle.jdbc.OracleBfile
オブジェクトを受け入れます。これらのメソッドを使用してBFILEに書き込みます。 -
getBfile
、setBfile
およびupdateBfile
メソッドのかわりに、getBFILE
、setBFILE
およびupdateBFILE
メソッドを使用することをお薦めします。たとえば、setBfile
メソッドのかわりにsetBFILE
メソッドを使用します。
-
15.7 LOBに関するJDBCのベスト・プラクティス
データベースへのラウンドトリップ回数を減らすと、アプリケーションのパフォーマンスを向上させることができます。この項では、データベースへのラウンドトリップ回数を最小限に抑える方法について説明します。
LOBデータの最大サイズがわかっていて、LOB全体に対して読取りまたは書込み操作を実行する場合は、次のガイドラインに従ってデータ・インタフェースを使用してください。
- 読取り操作の場合、
DefineColumnType
メソッドを使用して、LOBを文字型またはバイナリ型として定義します。 - 書込み操作の場合、
setString
またはsetBytes
メソッドを使用して、LOBを文字型またはバイナリ型としてバインドします。
LOBデータの最大サイズがわからない場合は、読取り操作のためのLOBプリフェッチ操作でLOB APIを使用します。また、列内のLOB値の大部分を収容できる値に、LOBプリフェッチ・サイズを定義します。
関連項目:
LOBプリフェッチ