この章では、データ・インタフェースまたはロケータ・インタフェースのいずれかを使用して、ラージ・オブジェクト(LOB)にアクセスし、操作するために、Java Database Connectivity(JDBC)を使用する方法について説明します。
以前のリリースでは、Oracle JDBCドライバには、Oracle Databaseで多くの操作を実行するために、標準JDBC型に対するOracle拡張機能が必要でした。JDBC 3.0ではOracle拡張機能を使用する必要が少なくなり、JDBC 4.0ではこの制限はほとんどなくなりました。java.sql
およびjavax.sql
パッケージについてはJavasoft Javadocを、Oracle拡張機能の詳細はOracle JDBC Javadocを参照してください。
この章の内容は次のとおりです。
Oracle Database 10gより前には、LOBの最大サイズが2^32バイトでした。この制限は、Oracle Database 10gで削除されており、現在の最大サイズは使用可能な物理記憶域のサイズと同じです。
関連項目: 『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』 |
Oracleデータベースでは、次の4つのLOBデータ型をサポートします。
バイナリ・ラージ・オブジェクト(BLOB)
このデータ型は、非構造バイナリ・データに使用されます。
キャラクタ・ラージ・オブジェクト(CLOB)
このデータ型は、文字データに使用されます。
各国語キャラクタ・ラージ・オブジェクト(NCLOB)
このデータ型は、各国語文字データに使用されます。
BFILE
このデータ型は、データベース表領域外の、オペレーティング・システム・ファイルに格納されるラージ・バイナリ・データ・オブジェクトに使用されます。
BLOB、CLOBおよびNCLOBは、データベース表領域に永続的に格納され、これらのデータ型に対する操作はすべて、トランザクション制御の下で実行されます。
BFILEは、Oracle独自のデータ型で、3次ストレージ・デバイス(ハード・ディスク、ネットワーク・マウント・ファイルシステム、CD-ROM、PhotoCDおよびDVDなど)上のデータベース表領域外にあるデータに読取り専用アクセスが可能です。BFILEデータは、トランザクション制御下にはなく、データベース・バックアップでは保存されません。
PL/SQL言語では、LOBデータ型がサポートされ、JDBCインタフェースにより、PL/SQLのプロシージャまたはファンクションへのINパラメータの引渡しや、OUTパラメータや戻り値の取出しが可能です。PL/SQLでは、LOBを含むすべてのデータ型に値セマンティクスを使用しますが、参照セマンティクスはBFILEに対してのみです。
Oracle Database 11gリリース1(11.1)では、LOBのまったく新しい記憶域としてOracle SecureFilesが導入されました。
関連項目: Oracle Database SecureFiles and Large Objects開発者ガイド |
Oracle SecureFilesの次の機能は、既存のAPIを介してJDBCプログラムで透過的に使用可能です。
SecureFile圧縮により、データを圧縮してディスク容量を節約できます。
SecureFile暗号化では、暗号化されたデータのランダムな読取りおよび書込みを可能にする新しい暗号化ツールが導入されました。
重複では、Oracle Databaseの重複LOBデータが自動検出され、データを一部のみ保存することで容量が節約されます。
LOBデータ・パス・最適化には、記憶域レイヤーの上の論理キャッシュと新しいキャッシング・モードが含まれます。
高いパフォーマンスの容量管理。
setLobOptions
およびgetLobOptions
APIについては『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。コール可能文を使用してJDBCからアクセスすることもできます。
Oracle SecureFilesの次の機能は、既存のAPIに対する更新により、データベース内で実装されます。
isSecureFileメソッド
Oracle Database 11gリリース2(11.2)から、BLOB
またはCLOB
データによりOracle SecureFile記憶域が使用されているかどうかをチェックできるようになりました。このチェックを行うには、oracle.sql.BLOB
クラスまたはoracle.sql.CLOB
クラスの次のメソッドを使用します。
public boolean isSecureFile() throws SQLException
このメソッドからtrue
が戻された場合、データはSecureFile記憶域を使用しています。
関連項目: Oracle Database SecureFiles and Large Objects開発者ガイド |
Oracle SecureFilesのゼロコピーI/O
Oracle Database 11gリリース2(11.2)JDBCドライバの発表により、Oracle SecureFiles操作のパフォーマンスが大幅に向上しました。これは、Oracle Net Servicesで、バッファ管理を改善するためにゼロコピーI/Oフレームワークが使用されるようになったためです。
Oracle Database 11gリリース2(11.2)では、新しい接続プロパティoracle.net.useZeroCopyIO
が導入されました。このプロパティは、ゼロコピーI/Oプロトコルを有効または無効にするために使用できます。この接続プロパティは、定数OracleConnection.CONNECTION_PROPERTY_THIN_NET_USE_ZERO_COPY_IO
として定義されています。ゼロコピーI/Oフレームワークを無効にする場合は、この接続プロパティの値をfalse
に設定してください。この接続プロパティのデフォルト値はtrue
です。
この項の内容は次のとおりです。
Oracle 11.2ドライバでは、LOBの内容全体の書込みと読取りができる効率的なメカニズムを提供しています。これは、データ・インタフェースと呼ばれます。このデータ・インタフェースでは、標準JDBCメソッド(getString
やsetBytes
など)を使用して、LOBデータの読取りと書込みを行います。多くの場合、これによってコーディングが簡素化され、処理が速くなります。標準のjava.sql.Blob
、java.sql.Clob
およびjava.sql.NClob
インタフェースと異なり、これにはランダム・アクセス機能はなく、2147483648要素を超えるデータにはアクセスできません。
Oracle Database 11gリリース2(11.2)では、PreparedStatement
のsetBytes
、setBinaryStream
、setString
、setCharacterStream
およびsetAsciiStream
メソッドが、BLOB
、CLOB
およびNCLOB
ターゲット列を処理する能力を強化するために拡張されています。
注意: この強化は、読取り専用のBFILE データには影響がありません。 |
JDBC Oracle Call Interface(OCI)とThinドライバには、byte
配列やString
のサイズに制限はなく、ストリーム・ファンクションに指定された長さには、Java言語の制限を除けば、制限はありません。
注意: Javaでは、配列サイズは正のJavaint または2147483648要素に制限されています。 |
サーバー側内部ドライバについては、現在INSERT
文などのSQL文の操作に4000バイトという制限があります。この制限はPL/SQL文には適用されません。INSERT
文については、次のようにPL/SQLブロックにラップするという簡単な回避方法があります。
BEGIN INSERT id, c INTO clob_tab VALUES(?,?); END;
大量のデータに対する次のような入力モードの自動切替えは留意する必要があります。
次の3つの入力モードがあります。
直接バインディグ
このバインディングは、サイズに制限がありますが、最も効率的です。すべての入力列のデータを、サーバーに送信するデータのブロックにインラインで配置します。バッチの複数回実行を含め、すべてのデータは1回のネットワーク操作で送信されます。
ストリーム・バインディング
このバインディングでは、データが最後に配置されます。バッチ・サイズは1つに制限され、完了に複数回のラウンドトリップが必要になる場合があります。
LOBバインディング
このバインディングでは、一時LOBを作成し、データをLOBにコピーして、LOBロケータをバインドします。一時LOBは、実行後、自動的に解放されます。一時LOBを作成してから、LOBに書き込む操作には、複数回のラウンドトリップが必要です。ロケータの入力はバッチ処理されます。
SQL文の場合
setBytes
およびsetBinaryStream
メソッドでは、4001バイト未満のデータには直接バインディングを使用します。
setBytes
およびsetBinaryStream
メソッドでは、4000バイトを超えるデータにはストリーム・バインディングを使用します。
JDBC 4.0では、新しい形式のsetAsciiStream
、setBinaryStream
およびsetCharacterStream
メソッドが導入されました。メソッドが長さとして長い引数を取る形式では、2147483648を超える長さにはLOBバインディングを使用します。長さを指定しない形式では、常にLOBバインディングを使用します。
setString
、setCharacterStream
およびsetAsciiStream
メソッドでは、32767文字未満のデータには直接バインディングを使用します。
setString
、setCharacterStream
およびsetAsciiStream
メソッドでは、32766文字を超えるデータにはストリーム・バインディングを使用します。
新しい形式のsetCharacterStream
メソッドは、長さの引数としてlong
引数を取り、JDBC 4.0では、2147483647を超える長さにLOBバインディングを使用します。長さを指定しない形式では、常にLOBバインディングを使用します。
PL/SQL文
setBytes
およびsetBinaryStream
メソッドでは、32767バイト未満のデータには直接バインディングを使用します。
注意: 基礎となるデータベースがOracle Databaseリリース10.xの場合、11gリリース2(11.2)JDBCドライバを使用していても、データ・サイズ制限は32512バイトです。 |
setBytes
およびsetBinaryStream
メソッドでは、32766バイトを超えるデータにはLOBバインディングを使用します。
setString
、setCharacterStream
およびsetAsciiStream
メソッドでは、データベース・キャラクタ・セットで32767バイト未満のデータには直接バインディングを使用します。
注意: 基礎となるデータベースがOracle Databaseリリース10.xの場合、11gリリース2(11.2)JDBCドライバを使用していても、データ・サイズ制限は32512バイトです。 |
setString
、setCharacterStream
およびsetAsciiStream
メソッドでは、データベース・キャラクタ・セットで32766バイトを超えるデータにはLOBバインディングを使用します。
大量データの入力モードの自動切替えは、一部のプログラムに影響を与えます。以前は、32766文字を超えるString
値にsetString
を使用しようとすると、ORA-17157
エラーが発生していました。現在は、ターゲット・パラメータの型に応じて、文の実行中にエラーが発生する場合と、操作が成功する場合があります。
もう1つの影響は、自動切替えの結果、パラメータの型の変更に適合させるために追加のサーバー側解析が実行される場合があることです。その結果、文が繰り返し実行されてデータ・サイズが制限の上下に変動すると、パフォーマンスに影響が生じます。ストリーム・モードへの切替えはバッチ処理にも影響を与えます。
LOBへの変換の強制
oracle.jdbc.OraclePreparedStatement
インタフェースにあるsetBytesForBlob
およびsetStringForClob
メソッドでは、すべてのデータ・サイズにLOBバインディングを使用します。
Oracle Database 10gリリース1(10.1)のSetBigStringTryClob
接続プロパティは、使用されなくなるか不要になりました。
ResultSet
およびCallableStatement
のgetBytes
、getBinaryStream
、getSting
、getCharacterStream
およびgetAsciiStream
メソッドは、BLOB
、CLOB
およびBFILE
列またはOUT
パラメータと連係するよう拡張されています。これらのメソッドは、2147483648未満の長さのすべてのLOB
に機能します。
注意: getString メソッドとgetNString メソッドを使用してBLOB列値を取得することはできません。getNString メソッドの詳細は、「JDK 1.6での各国語キャラクタ・セット用の新しいメソッド」を参照してください。 |
データ・インタフェースはドライバ内でのLOB
ロケータへのアクセスにより動作し、アプリケーション・プログラミングに対して透過的に行われます。サポートされているすべてのリリースのデータベース(Oracle Database 9.2以降)で機能します。リリース11.1以降のデータベースでは、LOBのプリフェッチを使用して、必要なデータベース・ラウンドトリップを減らすかなくすことができます。詳細は、「LOBのプリフェッチ」を参照してください。
BLOB
またはCLOB
データの読取りおよび書込みには、LONG
RAW
およびLONG
データと同じストリーミング・メカニズムを使用することもできます。BFILE
データは、同じストリーミング・メカニズムを使用して読み取れます。読み取るには、列に対してdefineColumnType(nn,
Types.LONGVARBINARY)
またはdefineColumnType(nn,Types.LONGVARCHAR)
を使用します。これによって、ダイレクト・ストリームがデータに対してLONG RAW
またはLONG
列であるかのように作成されます。この技術はOracle Database 10gリリース1(10.1)以降に限定されます。
PL/SQLの要件は、IN OUTパラメータの入力と出力に同じJava型を使用する必要があります。この章で説明した拡張機能による型の自動切替えが原因で、これに関して問題が発生する場合があります。
ストアド・プロシージャのIN
OUT
CLOB
パラメータがあり、このパラメータの値を設定するためにsetString
を使用するとします。IN
およびOUT
パラメータについて、バインドを同じ型にする必要があります。データ・サイズが判明していないかぎり、入力モードの自動切替えによって問題が発生します。たとえば、入力データおよび出力データの両方が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
を使用できます。
非常に大きなbyte
配列またはString
が作成されるために、Javaメモリー管理システムのパフォーマンスに影響が生じることに注意してください。Java仮想マシン(JVM)ベンダーが提供する情報を参照して、大量のデータ要素がメモリー管理に与える影響を理解し、かわりにストリーム・インタフェースを使用することを検討してください。
ロケータは少量データ構造体で、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 11 gでは、Oracle JDBCドライバは、ojdbc6.jar
ではJDBC 4.0 java.sql.NClob
インタフェースをサポートします。これはJDK 1.6でコンパイルし、JRE 6以上で使用する必要があります。ojdbc5.jar
ではJDBC 3.0標準をサポートします。これはJRE 5以上で使用する必要があります。
これに対し、oracle.sql.BFILE
はOracle拡張機能で、対応するjava.sql
インタフェースはありません。
Oracle Databaseの旧リリースのoracle.sql.CLOB
およびoracle.sql.BLOB
インタフェースで提供されているいくつかの読取りおよび書込みメソッドなど、一部のOracle拡張機能は、必要でなくなるか、非推奨となりました。アプリケーションを標準JDBC 3.0インタフェースに移植するか、JDK1.6以上とojdbc6.jar
を使用している場合は、JDBC 4.0インタフェースに移植する必要があります。
関連項目: 詳細は、Javadocを参照してください。 |
LOBのプリフェッチ
Oracle Database 11gリリース2(11.2)JDBCドライバの場合、通常のフェッチ操作中にロケータとともにLOBデータの始めをプリフェッチするのと同様に、LOBの長さやチャンク・サイズなどのメタデータをプリフェッチすることで、ラウンドトリップの回数を減らします。LOB列を選択して結果セットに入れる場合、サーバーやJDBCドライバの新機能により、ロケータがフェッチされると、データの一部またはすべてをクライアントにプリフェッチできます。後続の読取りAPIコールでは、プリフェッチ・バッファからデータが取得され、データベースへのラウンドトリップは不要になります。
プリフェッチ・サイズは、BLOBの場合はバイトで、CLOBの場合は文字数で指定されます。接続プロパティoracle.jdbc.defaultLobPrefetchSize
を設定することで指定できます。このプロパティの値は、次の2つの方法でオーバーライドできます。
文レベル: oracle.jdbc.OracleStatement.setLobPrefetchSize(int)
メソッドを使用
列レベル: 長さを引数として取るdefineColumnType
メソッドの形式を使用
デフォルトのプリフェッチ・サイズは4000です。
注意: 大型LOBのプリフェッチ・サイズを、行プリフェッチ・サイズや多数のLOB列と一緒に設定するときには、予想されるメモリー消費に注意してください。 |
関連項目: 詳細は、Javadocを参照してください。 |
JDBC 4.0の新しいLOB API
Oracle Database 11gリリース1(11.1)から、新しいインタフェースjava.sql.NClob
が導入されました。Oracleドライバが、ojdbc5.jar
とojdbc6.jar
でoracle.sql.NCLOB
インタフェースを実装します。ojdbc6.jar
では、java.sql.NClob
の実装が宣言され、ojdbc5.jar
では、oracle.sql.CLOB
インタフェースを拡張するのみです。
Oracleドライバにより、新しいファクトリ・メソッドcreateBlob
、createClob
およびcreateNClob
が、一時LOBを作成するためにjava.sql.Connection
インタフェースで実装されます。
JDK 1.6から、java.sql.Blob
、java.sql.Clob
およびjava.sql.NClob
インタフェースに、LOBを解放し、関連付けられたリソースを解放する新しいfree
メソッドが導入されました。Oracleドライバはこのメソッドを使用して、一時LOBを解放します。
一時LOBは、一時データの格納に使用できます。データは、通常の表領域ではなく、一時表領域に格納されます。不要になった一時LOBは解放する必要があります。解放しない場合、LOBによって使用されている一時表領域は再生されません。
一時LOBは、表に挿入できます。挿入すると、LOBの永続的なコピーが作成されて格納されます。
注意: 一時LOBを挿入する方が便利な場合があります。たとえば、LOBデータが相対的に小さい場合は、空のロケータを取り出すデータベース・ラウンドトリップのコストに比べて、データをコピーするオーバーヘッドが小さくなります。データは、最初はサーバーの一時表領域に格納され、その後永続記憶域に移されるためです。 |
一時LOBは、oracle.sql.BLOB
クラスとoracle.sql.CLOB
クラスの両方で定義されているstatic
メソッドcreateTemporary
で作成します。一時LOBを解放するには、freeTemporary
メソッドを使用します。
JDBC 4.0で利用できる接続ファクトリ・メソッドを使用することにより、一時LOBを作成することもできます。詳細は、「LOBの作成」を参照してください。
isTemporary
メソッドをコールすることで、LOBが一時LOBかどうかをテストできます。LOBがcreateTemporary
メソッドをコールして作成された場合、isTemporary
メソッドは、true
を戻し、それ以外の場合はfalse
を戻します。
一時LOBを解放するには、freeTemporary
メソッドをコールします。セッションまたはコールを終了する前に、一時LOBを解放してください。
注意:
|
JDK 1.5でのテンポラリNCLOBの作成
各国語キャラクタ・ラージ・オブジェクト(NCLOB)はcreateTemporary
メソッドの変種を使用して作成します。
JDK 1.6でのテンポラリNCLOBの作成
JDBC 4.0ではNCLOBが直接サポートされています。java.sql.Connection
インタフェースの標準のファクトリ・メソッドを使用してNCLOBを作成することができます。
この項では、LOBのオープンとクローズの方法について説明します。この機能は、oracle.sql.BLOB
およびoracle.sql.CLOB
インタフェースの次のメソッドを使用して、JDBC実装されます。
注意: LOBは必ずしもオープンおよびクローズする必要はありません。パフォーマンス上の理由から、LOBのオープンとクローズを選択できます。 |
関連項目: 『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』 |
void open (int mode)
void close()
boolean isOpen()
Open/Close
コール操作内部でLOB操作をラップしない場合、LOBは変更のたびに暗黙的にオープンおよびクローズされ、ドメイン索引上でトリガーが起動されます。この場合、LOBを変更するとただちに、LOBのドメイン索引がすべて更新されることに注意してください。したがって、ドメインLOB索引は常に有効となり、同じトランザクション内でいつでも使用できます。
Open/Close
コール操作の内部でLOB操作をラップすると、LOBが変更されるたびにトリガーが起動されることはありません。かわりに、Close
がコールされた時点で、ドメイン索引に関するトリガーが起動します。たとえば、close
メソッドをコールするまでドメイン索引が更新されないようにアプリケーションを設計できます。ただし、これは、LOB上のドメイン索引がOpen/Close
コールの間は無効であることを意味します。
LOBを開くには、open
メソッドまたはopen(int)
メソッドをコールします。その後、そのLOBに関連付けられたトリガーを起動することなく、LOBの読取りまたは書込み操作を実行できます。LOBへのアクセスが終了後、close
メソッドをコールしてLOBをクローズします。LOBをクローズすると、そのLOBに関連付けられたトリガーが起動します。
isOpen
メソッドをコールすると、LOBがオープンまたはクローズしているかどうかを確認できます。open(int)
メソッドをコールしてLOBをオープンした場合は、引数の値がoracle.sql.BLOB
クラスおよびoracle.sql.CLOB
クラスで定義されたMODE_READONLY
またはMODE_READWRITE
である必要があります。MODE_READONLY
を使用してLOBをオープンした場合は、そのLOBに書込みを試みるとSQL例外が発生します。
注意:
|
この項では、ファイル・ロケータを使用してBFILEからデータを読み取る方法を説明します。この項の内容は次のとおりです。
BFILEロケータの取出し
BFILEデータ型とoracle.sql.BFILE
クラスは、Oracle独自のものです。したがって、これらには標準インタフェースはありません。この型のデータには、Oracle拡張機能を使用する必要があります。
標準JDBC結果セットまたはBFILEロケータを含むコール可能文オブジェクトがある場合は、標準結果セットのgetObject
メソッドを使用して、ロケータにアクセスできます。このメソッドは、oracle.sql.BFILE
オブジェクトを戻します。
また、結果セットをOracleResultSet
にキャストするか、コール可能文をOracleCallableStatement
にキャストし、getOracleObject
またはgetBFILE
メソッドを使用することにより、ロケータにアクセスすることもできます。
注意: getObject またはgetOracleObject メソッドを使用している場合は、必要に応じて出力をキャストしてください。 |
ロケータがあれば、oracle.sql.BFILE
内のAPIによりBFILEデータにアクセスできます。これらのAPIは、java.sql.BLOB
インタフェースの読取りメソッドに似ています。
BFILESへの書込み
BFILEの内容にデータは書き込めませんが、oracle.sql.BFILE
のインスタンスをSQL文またはPL/SQLプロシージャへの入力として使用できます。これは次のいずれかを実行することで行えます。
標準のsetObject
メソッドを使用します。
文をOraclePreparedStatement
またはOracleCallableStatement
にキャストし、setOracleObject
またはsetBFILE
メソッドを使用します。これらのメソッドは、パラメータ索引およびoracle.sql.BFILE
オブジェクトを入力として取ります。
注意:
|
BFILEは読取り専用です。データの本体はオペレーティング・システム(OS)のファイルシステムにあり、OSのツールとコマンドを使用しないと書き込めません。JDBCから、またはSQLを実行する別の方法を使用して、適切なSQL文を実行することにより、既存の外部ファイル用のBFILEを作成できます。しかし、BFILEが参照するOSファイルSQLまたはJDBCでは作成できません。これは、サーバー・ファイルシステムにアクセスするプロセスによって外部的にしか作成されません。
注意:
|