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として格納できます。

関連項目:

永続LOB

SecureFilesは、データベース表での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ドライバにより、ファクトリ・メソッドcreateBlobcreateClobおよび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.Blobjava.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.Blobjava.sql.Clobおよびjava.sql.NClobインタフェースと異なり、このデータ・インタフェースにはランダム・アクセス機能はなく、LOBロケータを使用していないので、サイズが2 GBを超えるデータにはアクセスできません。

LOB用のデータ・インタフェースを使用すると、対応するレガシー・データ型(VARCHAR2LONGRAWなど)に格納されている場合と同様に、文字データとバイナリ・データをLOB列に格納して操作できます。この節では、以下のトピックについて説明します。

15.4.1 入力

PreparedStatementインタフェースのsetBytessetBinaryStreamsetStringsetCharacterStreamおよびsetAsciiStreamメソッドは、BLOBCLOBおよびNCLOBターゲット列を処理する機能を強化するために拡張されています。データの長さが不明である場合は、パフォーマンスを向上させるために、データの長さをパラメータとして受け入れるsetBinaryStreamまたはsetCharacterStreamメソッドのバージョンを使用します。

ノート:

これらのメソッドは、読取り専用のBFILEデータでは機能しません。

JDBC Oracle Call Interface (OCI)とThinドライバには、byte配列やStringのサイズに制限はなく、ストリーム・ファンクションに指定された長さには、Java言語の制限を除けば、制限はありません。

ノート:

Javaでは、配列サイズは正のJava intまたは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つの形式のsetAsciiStreamsetBinaryStreamおよびsetCharacterStreamメソッドがあります。長さとしてlong引数を取る形式では、2147483648を超える長さにはLOBバインディングを使用します。長さを指定しない形式では、常にLOBバインディングを使用します。

    • setStringsetCharacterStreamおよびsetAsciiStreamメソッドでは、32767文字未満のデータには直接バインディングを使用します。

    • setStringsetCharacterStreamおよびsetAsciiStreamメソッドでは、32766文字を超えるデータにはストリーム・バインディングを使用します。

  • PL/SQL文の場合

    • setBytesおよびsetBinaryStreamメソッドでは、32767バイト未満のデータには直接バインディングを使用します。

    • setBytesおよびsetBinaryStreamメソッドでは、32766バイトを超えるデータにはLOBバインディングを使用します。

    • setStringsetCharacterStreamおよびsetAsciiStreamメソッドでは、データベース文字セットで32767バイト未満のデータには直接バインディングを使用します。

    • setStringsetCharacterStreamおよびsetAsciiStreamメソッドでは、データベース文字セットで32766バイトを超えるデータにはLOBバインディングを使用します。

  • LOBへの変換の強制

    oracle.jdbc.OraclePreparedStatementインタフェースにあるsetBytesForBlobおよびsetStringForClobメソッドでは、すべてのデータ・サイズにLOBバインディングを使用します。

入力モードの自動切替えの影響

大量データの入力モードの自動切替えは、一部のプログラムに影響を与えます。以前は、32766文字を超えるString値にsetStringメソッドを使用しようとすると、ORA-17157エラーが発生していました。現在は、ターゲット・パラメータの型に応じて、文の実行中にエラーが発生する場合と、操作が成功する場合があります。

もう1つの影響は、自動切替えの結果、パラメータの型の変更に適合させるために追加のサーバー側解析が実行される場合があることです。その結果、文が繰り返し実行されてデータ・サイズが制限の上下に変動すると、パフォーマンスに影響が生じます。ストリーム・モードへの切替えはバッチ処理にも影響を与えます。

15.4.2 出力

ResultSetおよびCallableStatementインタフェースのgetBytesgetBinaryStreamgetStringgetCharacterStreamおよびgetAsciiStreamメソッドは、BLOBCLOBおよび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.4.4 サイズの制限

非常に大きなbyte配列またはStringが作成されるために、Javaメモリー管理システムのパフォーマンスに影響が生じることに注意する必要があります。Java仮想マシン(JVM)ベンダーが提供する情報を参照して、大量のデータ要素がメモリー管理に与える影響を理解し、かわりにストリーム・インタフェースを使用することを検討してください。

15.5 LOBのロケータ・インタフェース

ロケータは少量データ構造体で、LOBの実際のデータへのアクセスに使用できる情報が格納されます。データベース表で、ロケータは表に直接格納されるのに対し、データはその表または別の記憶域に格納できます。

JDBC 4.0以降では、LOBに対する読取りおよび書込み操作を実行するために、java.sql.Blobjava.sql.Clobおよびjava.sql.NClobインタフェースを使用する必要があります。これらのインタフェースにより、LOBのデータにはランダム・アクセスできます。

Oracle実装クラスのoracle.sql.BLOBoracle.sql.CLOBおよびoracle.sql.NCLOBではロケータを格納し、それを使用してデータにアクセスします。oracle.sql.BLOBクラスとoracle.sql.CLOBクラスは、それぞれjava.sql.Blobインタフェースとjava.sql.Clobインタフェースを実装します。ojdbc6.jarでは、oracle.sql.NCLOBjava.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 Javadoc

15.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 Javadoc

15.5.2 LOBのオープン操作とクローズ操作

この項では、LOBのオープンとクローズの方法について説明します。

この項では、LOBのオープンとクローズの方法について説明します。この機能は、oracle.sql.BLOBおよびoracle.sql.CLOBインタフェースで使用可能な次のメソッドを使用して、JDBC実装されます。

  • void open (int mode)
  • void close()
  • boolean isOpen()

ノート:

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に書き込みます。

    • getBfilesetBfileおよびupdateBfileメソッドのかわりに、getBFILEsetBFILEおよびupdateBFILEメソッドを使用することをお薦めします。たとえば、setBfileメソッドのかわりにsetBFILEメソッドを使用します。

15.7 LOBに関するJDBCのベスト・プラクティス

データベースへのラウンドトリップ回数を減らすと、アプリケーションのパフォーマンスを向上させることができます。この項では、データベースへのラウンドトリップ回数を最小限に抑える方法について説明します。

LOBデータの最大サイズがわかっていて、LOB全体に対して読取りまたは書込み操作を実行する場合は、次のガイドラインに従ってデータ・インタフェースを使用してください。

  • 読取り操作の場合、DefineColumnTypeメソッドを使用して、LOBを文字型またはバイナリ型として定義します。
  • 書込み操作の場合、setStringまたはsetBytesメソッドを使用して、LOBを文字型またはバイナリ型としてバインドします。

LOBデータの最大サイズがわからない場合は、読取り操作のためのLOBプリフェッチ操作でLOB APIを使用します。また、列内のLOB値の大部分を収容できる値に、LOBプリフェッチ・サイズを定義します。

関連項目:

LOBプリフェッチ