この章では、Java Database Connectivity(JDBC)およびoracle.sql.*
クラスを使用して、ラージ・オブジェクト(LOB)ロケータとデータおよびバイナリ・ファイル(BFILE)ロケータとデータにアクセスして、操作する方法を説明します。この章では、次の項目について説明します。
注意:
|
LOBは、領域を最適化し効率的にアクセスできるようにして格納されます。JDBCドライバは、非構造化バイナリ・データで使用するバイナリ・ラージ・オブジェクト(BLOB)、文字データで使用するキャラクタ・ラージ・オブジェクト(CLOB)および各国語の文字データで使用する各国語キャラクタ・ラージ・オブジェクト(NCLOB)の3種類のLOBをサポートします。BLOB、CLOBおよびNCLOBデータは、ロケータを使用してアクセスおよび参照します。ロケータはデータベース表内に格納され、表の外部にあるBLOB、CLOBまたはNCLOBデータを指します。
BFILEは、データベース表領域外のオペレーティング・システム・ファイルに格納されたラージ・バイナリ・データ・オブジェクトです。これらのファイルは、参照セマンティクスを利用します。また、これらのファイルはハード・ディスク、CD-ROM、PhotoCD、DVDなどの3次ストレージ・デバイスにも配置できます。BLOBやCLOB、NCLOBと同様、BFILEは、ロケータによりアクセスまたは参照されます。ロケータは、データベース表内に格納され、BFILEデータを指します。
LOBデータを使用するには、最初に、LOBロケータを取り出す必要があります。その後、LOBデータの読取りまたは書込み、データ操作が実行できます。
JDBCドライバは、BLOB、CLOB、NCLOBおよびBFILEに対応した、次のoracle.sql.*
クラスをサポートします。
oracle.sql.BLOB
oracle.sql.CLOB
oracle.sql.NCLOB
oracle.sql.BFILE
oracle.sql.BLOB
クラス、oracle.sql.CLOB
クラスおよびoracle.sql.NCLOBクラスは、それぞれjava.sql.Blob
インタフェース、java.sql.Clob
インタフェースおよびjava.sql.NClob
インタフェースを実装します。これに対し、BFILE
はOracle拡張機能で、対応するjava.sql
インタフェースはありません。
これらのクラスのインスタンスは、これらのデータ型のロケータのみを含み、データは含みません。ロケータへのアクセス後に、データにアクセスをするために追加処理を行う必要があります。
注意: 新規LOB オブジェクトを作成する場合、oracle.jdbc.OracleConnection インタフェースのファクトリ・メソッドを使用します。 |
この項では、LOBロケータを使用し、Oracle DatabaseのBLOB、CLOBおよびNCLOBに対して、データの読取りおよび書込みを行う方法を説明します。この項には、次の項目が含まれます。
データベースからLOBロケータを取り出すとき、またはデータベースにLOBロケータを渡すときに使用可能なgetterおよびsetterメソッドには、標準のメソッドとOracle固有のメソッドがあります。この項には、次の項目が含まれます。
BLOB、CLOBまたはNCLOBロケータを含む標準JDBC結果セットまたはコール可能文がある場合は、次の標準getterメソッドを使用して、ロケータにアクセスできます。標準のgetBlob
、getClob
およびgetNClob
メソッドを使用できます。これらのメソッドはそれぞれ、java.sql.Blob
、Clob
およびNClob
オブジェクトを戻します。
注意: この項で説明する標準およびOracle固有のgetterメソッドはすべて、入力としてint 列索引またはString 列名を取ります。 |
結果セットをOracleResultSet
に取り出すか、またはコール可能文をOracleCallableStatement
にキャストすると、次のようにOracle拡張機能を使用できます。
getBlob
、getClob
およびgetNClob
を使用できます。これらのメソッドはそれぞれ、java.sql.Blob
、CLOB
およびNCLOB
オブジェクトを戻します。
getOracleObject
メソッドを使用することもできます。このメソッドは、oracle.sql.Datum
オブジェクトを戻し、出力を適切にキャストします。
例: 結果セットからのBLOB、CLOBおよびNCLOBロケータの取出し
BLOBロケータ用のblob_col
、CLOBロケータ用のclob_col
およびNCLOBロケータ用のnclob_col
という列を備えたlob_table
という表がデータベースにあるものとします。この例では、Statement
オブジェクトstmt
が作成済であるものとします。
まず、LOBロケータを標準結果セット内にSelectします。その後、LOBデータを適切なJavaクラス内に取り込みます。
// Select LOB locator into standard result set.
ResultSet rs =
stmt.executeQuery ("SELECT blob_col, clob_col, nclob_col FROM lob_table");
while (rs.next())
{
// Get LOB locators into Java container classes.
java.sql.Blob blob = (java.sql.Blob)rs.getObject(1);
java.sql.Clob clob = (java.sql.Clob)rs.getObject(2);
java.sql.NClob nclob = (java.sql.NClob)rs.getObject(3);
(...process...)
}
出力は、java.sql.Blob
、java.sql.Clob
およびjava.sql.NClob
にキャストされます。また、出力をoracle.sql.BLOB
、oracle.sql.CLOB
およびoracle.sql.NCLOB
にキャストして、oracle.sql.*
クラスが提供する拡張機能を利用する方法もあります。たとえば、前述のコードを次のように書きなおして、LOBロケータを取り出すこともできます。
// Get LOB locators into Java container classes.
oracle.sql.BLOB blob = (BLOB)rs.getObject(1);
oracle.sql.CLOB clob = (CLOB)rs.getObject(2);
oracle.sql.NCLOB nclob = (NCLOB)rs.getObject(3);
(...process...)
例: コール可能文からのCLOBロケータの取出し
LOB取出し用のコール可能文は、結果セットのメソッドと同一です。
たとえば、CLOB出力パラメータを取る関数func
をコールするOracleCallableStatement
インスタンスのocs
がある場合は、次のようにコール可能文を設定します。
この例では、出力パラメータの型コードとして、OracleTypes.CLOB
が登録されます。
OracleCallableStatement ocs = (OracleCallableStatement)conn.prepareCall("{? = call func()}"); ocs.registerOutParameter(1, OracleTypes.CLOB); ocs.execute(); oracle.sql.CLOB clob = ocs.getCLOB(1);
標準JDBCのプリコンパイルされたSQL文またはコール可能文がある場合は、標準setterメソッドを使用して、LOBロケータを渡せます。メソッドは次のように定義されます。
public void setBlob(int index, Blob value); public void setClob(int index, Clob value); public void setNClob(int index, NClob value);
Oracle固有のOraclePreparedStatement
またはOracleCallableStatement
がある場合、次のようにOracle拡張機能を使用できます。
例: BLOBロケータのプリコンパイルされたSQL文への引渡し
OraclePreparedStatement
オブジェクトops
と、my_blob
という名前のBLOBがある場合は、次のようにBLOBをデータベースに書き込みます。
OraclePreparedStatement ops = (OraclePreparedStatement)conn.prepareStatement ("INSERT INTO blob_table VALUES(?)"); ops.setBLOB(1, my_blob); ops.execute();
例: CLOBロケータのコール可能文への引渡し
OracleCallableStatement
オブジェクトocs
と、my_clob
という名前のCLOBがある場合は、次のようにCLOBをストアド・プロシージャproc
に入力します。
OracleCallableStatement ocs = (OracleCallableStatement)conn.prepareCall("{call proc(?))}"); ocs.setClob(1, my_clob); ocs.execute();
例: NCLOBロケータのコール可能文への引渡し
OracleCallableStatement
オブジェクトocs
と、my_nclob
という名前のNCLOBがある場合は、次のようにNCLOBをストアド・プロシージャproc
に入力します。
OracleCallableStatement ocs = (OracleCallableStatement)conn.prepareCall("{call proc(?))}"); ocs.setNClob(1, my_nclob); ocs.execute();
LOB
ロケータがあれば、JDBCメソッドを使用して、LOB
データの読取りおよび書込みができます。LOB
データは、Java配列またはストリームとしてインスタンス化されます。LONG
およびLONG RAW
データと異なり、接続されている間、LOB
データにはいつでもアクセスできます。
LOB
データの読取りおよび書込みを行う場合、java.sql.BLOB
、java.sql.CLOB
またはjava.sql.NCLOB
クラスのメソッドを適宜使用します。これらのクラスは、LOB
から入力ストリーム内への読取り、出力ストリームからLOB
内への書込み、LOB
の長さの決定およびLOB
のクローズなどの機能を提供します。
注意: LOB データを書き込むには、アプリケーションでLOB オブジェクトの書込みロックを取得する必要があります。SELECT FOR UPDATE を使用することで取得できます。また、自動コミット・モードを無効化する必要があります。 |
LOB
データの読取りおよび書込みを実行する際、次のメソッドを使用できます。
BLOB
から読み取るには、java.sql.BLOB
オブジェクトのgetBinaryStream
メソッドを使用して、BLOB
全体を入力ストリームとして取り出します。これにより、java.io.InputStream
オブジェクトが戻されます。
InputStream
オブジェクトの場合と同様に、オーバーロードしたread
メソッドの1つを使用してLOB
データを読み取り、完了時にclose
メソッドを使用します。
BLOB
に書き込むには、java.sql.BLOB
オブジェクトのsetBinaryStream
メソッドを使用して、BLOB
を出力ストリームとして取り出します。このメソッドは、BLOB
に書き戻されるjava.io.OutputStream
オブジェクトを戻します。
OutputStream
オブジェクトの場合と同様に、オーバーロードしたwrite
メソッドの1つを使用して、LOBデータを更新し、完了時にclose
メソッドを使用します。
CLOBから読み取るには、java.sql.CLOB
オブジェクトのgetAsciiStream
またはgetCharacterStream
メソッドを使用して、CLOB全体を入力ストリームとして取り出します。getAsciiStream
メソッドは、java.io.InputStream
オブジェクトのASCII入力ストリームを戻します。getCharacterStream
メソッドは、java.io.Reader
オブジェクトのUnicode
入力ストリームを戻します。
InputStream
またはReader
オブジェクトの場合と同様、オーバーロードしたread
メソッドの1つを使用して、LOBデータを読み取り、完了時にclose
メソッドを使用します。
java.sql.CLOB
オブジェクトのgetSubString
メソッドを使用すると、CLOBのサブセットをjava.lang.String
型の文字列として取り出せます。
CLOBに書き込むには、java.sql.CLOB
オブジェクトのsetAsciiStream
またはsetCharacterStream
メソッドを使用して、CLOBを出力ストリームとして取り出してから、CLOBに書き戻します。setAsciiStream
メソッドは、java.io.OutputStream
オブジェクトのASCII出力ストリームを戻します。setCharacterStream
メソッドは、java.io.Writer
オブジェクトのUnicode出力ストリームを戻します。
Stream
またはWriter
オブジェクトの場合と同様、オーバーロードしたwrite
メソッドの1つを使用して、LOB
データを更新し、完了時にflush
およびclose
メソッドを使用します。
NCLOBから読み取るには、java.sql.NCLOB
オブジェクトのgetAsciiStream
またはgetCharacterStream
メソッドを使用して、NCLOB全体を入力ストリームとして取り出します。getAsciiStream
メソッドは、java.io.InputStream
オブジェクトのASCII入力ストリームを戻します。getCharacterStream
メソッドは、java.io.Reader
オブジェクトのUnicode
入力ストリームを戻します。
InputStream
またはReader
オブジェクトの場合と同様、オーバーロードしたread
メソッドの1つを使用して、LOBデータを読み取り、完了時にclose
メソッドを使用します。
java.sql.NCLOB
オブジェクトのgetSubString
メソッドを使用すると、NCLOBのサブセットをjava.lang.String
型の文字列として取り出せます。
NCLOBに書き込むには、oracle.sql.NCLOB
オブジェクトのsetAsciiStream
またはsetCharacterStream
メソッドを使用して、NCLOBを出力ストリームとして取り出してから、NCLOBに書き戻します。setAsciiStream
メソッドは、java.io.OutputStream
オブジェクトのASCII出力ストリームを戻します。setCharacterStream
メソッドは、java.io.Writer
オブジェクトのUnicode出力ストリームを戻します。
Stream
またはWriter
オブジェクトの場合と同様、オーバーロードしたwrite
メソッドの1つを使用して、LOB
データを更新し、完了時にflush
およびclose
メソッドを使用します。
例: BLOBデータの読取り
oracle.sql.BLOB
クラスのgetBinaryStream
メソッドを使用して、BLOBデータを読み取ります。getBinaryStream
メソッドは、バイナリ・ストリームを介してBLOBデータにアクセスします。
次の例は、getBinaryStream
メソッドを使用してBLOBデータをバイト・ストリーム内に読み取り、次に、バイト・ストリームを読み取ってバイト配列に格納します。読み取ったバイト数も戻します。
// Read BLOB data from BLOB locator. InputStream byte_stream = my_blob.getBinaryStream(1L); byte [] byte_array = new byte [10]; int bytes_read = byte_stream.read(byte_array); ...
例: CLOBデータの読取り
次の例では、getCharacterStream
メソッドを使用して、CLOB
データをUnicode文字ストリーム内に読み取ります。次に、文字ストリームを読み取って文字配列に格納します。読み取った文字数も戻します。
// Read CLOB data from CLOB locator into Reader char stream. Reader char_stream = my_clob.getCharacterStream(1L); char [] char_array = new char [10]; int chars_read = char_stream.read (char_array, 0, 10); ...
例: NCLOBデータの読取り
次の例では、getCharacterStream
メソッドを使用して、NCLOB
データをUnicode文字ストリーム内に読み取ります。次に、文字ストリームを読み取って文字配列に格納します。読み取った文字数も戻します。
// Read NCLOB data from NCLOB locator into Reader char stream. Reader char_stream = my_nclob.getCharacterStream(1L); char [] char_array = new char [10]; int chars_read = char_stream.read (char_array, 0, 10); ...
次の例では、oracle.sql.NCLOB
クラスのgetAsciiStream
メソッドを使用して、NCLOBデータをASCII文字ストリーム内に読み取ります。次に、ASCIIストリームを読み取ってバイト配列に格納します。読み取った文字数も戻します。
// Read NCLOB data from NCLOB locator into Input ASCII character stream Inputstream asciiChar_stream = my_nclob.getAsciiStream(1L); byte[] asciiChar_array = new byte[10]; int asciiChar_read = asciiChar_stream.read(asciiChar_array,0,10);
例: BLOBデータの書込み
oracle.sql.BLOB
オブジェクトのsetBinaryOutputStream
メソッドを使用して、BLOBデータを書き込みます。
次の例では、データのベクトルをバイト配列内に読み取り、setBinaryOutputStream
メソッドを使用して、文字データの配列をBLOBに書き込みます。
java.io.OutputStream outstream; // read data into a byte array byte[] data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // write the array of binary data to a Blob outstream = ((BLOB)my_blob).setBinaryOutputStream(1L); outstream.write(data); ...
例: CLOBデータの書込み
setCharacterStream
メソッドまたはsetAsciiStream
メソッドを使用して、データをCLOBに書き込みます。setCharacterStream
メソッドは、Unicode
出力ストリームを戻します。setAsciiStream
メソッドは、ASCII出力ストリームを戻します。
次の例では、データのベクトルを文字配列内に読み取り、setCharacterStream
メソッドを使用して文字データの配列をCLOBに書き込みます。
java.io.Writer writer; // read data into a character array char[] data = {'0','1','2','3','4','5','6','7','8','9'}; // write the array of character data to a Clob writer = ((CLOB)my_clob).setCharacterStream(); writer.write(data); writer.flush(); writer.close(); ...
次の例では、データのベクトルをバイト配列内に読み取り、setAsciiStream
メソッドを使用して、ASCIIデータの配列をCLOBに書き込みます。
java.io.OutputStream out; // read data into a byte array byte[] data = {'0','1','2','3','4','5','6','7','8','9'}; // write the array of ascii data to a CLOB out = clob.setAsciiStream(); out.write(data); out.flush(); out.close();
例: NCLOBデータの書込み
setCharacterStream
メソッドまたはsetAsciiStream
メソッドを使用して、データをNCLOBに書き込みます。setCharacterStream
メソッドは、Unicode
出力ストリームを戻します。setAsciiStream
メソッドは、ASCII出力ストリームを戻します。
次の例では、データのベクトルを文字配列内に読み取り、setCharacterStream
メソッドを使用して文字データの配列をNCLOBに書き込みます。
java.io.Writer writer; // read data into a character array char[] data = {'0','1','2','3','4','5','6','7','8','9'}; // write the array of character data to an NClob writer = ((NCLOB)my_nclob).setCharacterStream(); writer.write(data); writer.flush(); writer.close(); ...
次の例では、データのベクトルをバイト配列内に読み取り、setAsciiStream
メソッドを使用して、ASCIIデータの配列をNCLOBに書き込みます。
java.io.OutputStream out; // read data into a byte array byte[] data = {'0','1','2','3','4','5','6','7','8','9'}; // write the array of ascii data to a NClob out = nclob.setAsciiStream(); out.write(data); out.flush(); out.close();
表にBLOB
列、CLOB
列またはNCLOB
列を作成し、データを移入するには、SQL文を使用します。
注意: Javaのnew 文を使用して、アプリケーションで新規のBLOBロケータ、CLOBロケータまたはNCLOBロケータを作成することはできません。SQL操作でロケータを作成した後、そのロケータをアプリケーションで選択するか、oracle.jdbc.OracleConnection インタフェースからファクトリ・メソッドを使用して選択する必要があります。 |
SQLのCREATE TABLE
文を使用して表にBLOB、CLOBまたはNCLOB列を作成し、LOBにデータを移入します。これには、表内でのLOBエントリの作成、LOBロケータの取出し、およびデータのLOBへのコピーが含まれます。
新しい表でのBLOB、CLOBまたはNCLOB列の作成
新しい表にBLOB、CLOBまたはNCLOB列を作成するには、SQLのCREATE TABLE
文を使用します。次の例では、新しい表にBLOB
列を作成します。この例では、Connection
オブジェクトconn
およびStatement
オブジェクトstmt
を作成してあるものとします。
String cmd = "CREATE TABLE my_blob_table (x VARCHAR2 (30), c BLOB)"; stmt.execute (cmd);
この例では、VARCHAR2
列は1や2などの行番号を表し、BLOB
列にはBLOBデータのロケータが格納されます。
新しい表でのBLOB、CLOBまたはNCLOB列へのデータ移入
この例では、ストリームからデータを読み取って、BLOB、CLOBまたはNCLOB列に移入する方法を示します。Connection
オブジェクトconn
およびStatement
オブジェクトstmt
は、すでに作成してあるものとします。表my_blob_table
は、前述の項で作成した表です。
次の例では、john.gif
ファイルをBLOBに書き込みます。
まず、SQL文を使用してBLOBエントリを表の中に作成します。empty_blob
関数を使用して、BLOBロケータを作成します。
stmt.execute ("INSERT INTO my_blob_table VALUES ('row1', empty_blob())");
表からBLOBロケータを取り出します。
BLOB blob; cmd = "SELECT * FROM my_blob_table WHERE X='row1' FOR UPDATE"; ResultSet rset = stmt.executeQuery(cmd); rset.next(); BLOB blob = ((OracleResultSet)rset).getBLOB(2);
注意: 自動コミット・モードを無効化する必要があります。 |
john.gif
ファイル用のファイル・ハンドラを宣言し、ファイルの長さを出力します。この値は、ファイル全体がBLOB内に読み取られたことを保証するために使用されます。次に、FileInputStream
オブジェクトを作成してファイルの内容を読み取り、OutputStream
オブジェクトを作成してBLOBをストリームとして取り出します。
File binaryFile = new File("john.gif"); System.out.println("john.gif length = " + binaryFile.length()); FileInputStream instream = new FileInputStream(binaryFile); OutputStream outstream = blob.setBinaryStream(1L);
getBufferSize
をコールして、BLOBへの書込みに使用する理想的なバッファ・サイズを取り出し、buffer
バイト配列を作成します。
int size = blob.getBufferSize(); byte[] buffer = new byte[size]; int length = -1;
read
メソッドを使用してファイルをバイト配列buffer
内に読み取り、次にwrite
メソッドを使用してそれをBLOBに書き込みます。完了時に、入力および出力ストリームをクローズして、変更をコミットします。
while ((length = instream.read(buffer)) != -1) outstream.write(buffer, 0, length); instream.close(); outstream.close(); conn.commit();
データがBLOB、CLOBまたはNCLOB内に格納されると、データの操作が可能になります。
BLOB、CLOBまたはNCLOBロケータが表内に格納されると、ロケータが指すデータへのアクセスおよび操作が可能になります。データへのアクセスおよび操作を行うには、最初に、結果セットまたはコール可能文からロケータを選択する必要があります。
ロケータの選択後に、BLOB、CLOBまたはNCLOBデータを取り出せます。BLOB、CLOBまたはNCLOBデータの取出し後、任意の方法でデータを操作できます。
この例は、前の項の例からの継続です。SQL SELECT
文を使用して、表my_blob_table
でBLOBロケータを選択し、結果セットに格納します。データ操作の結果として、BLOBの長さがバイト単位で出力されます。
// Select the blob - what we are really doing here // is getting the blob locator into a result set BLOB blob; cmd = "SELECT * FROM my_blob_table"; ResultSet rset = stmt.executeQuery (cmd); // Get the blob data - cast to OracleResult set to // retrieve the data in oracle.sql format String index = ((OracleResultSet)rset).getString(1); blob = ((OracleResultSet)rset).getBLOB(2); // get the length of the blob int length = blob.length(); // print the length of the blob System.out.println("blob length" + length); // read the blob into a byte array // then print the blob from the array byte bytes[] = blob.getBytes(1, length); blob.printBytes(bytes, length);
LOBのデータ・インタフェースは、LOBの内容全体の読取りと書込みができる効率的なメカニズムを提供しています。多くの場合、これによってコーディングが簡素化され、処理が早くなります。標準のjava.sql.Blob
およびjava.sql.Clob
インタフェースと、Oracle拡張機能のoracle.sql.BLOB
、oracle.sql.BFILE
およびoracle.sql.CLOB
のようなランダム・アクセス機能または2147483648要素を超えるアクセスは提供されていません。
入力
Oracle Database 11gリリース1(11.1)では、PreparedStatement
のsetBytes
、setBinaryStream
、setString
、setCharacterStream
およびsetAsciiStream
メソッドがBLOB
およびCLOB
パラメータに関して拡張されています。
JDBC Oracle Call Interface(OCI)およびThinドライバについては、byte
配列またはString
のサイズに制限がなく、ストリーム関数に指定される長さにも、Java言語による制限以外はありません。Java言語による制限とは、配列サイズが正のJava int
または2147483648要素に制限されるというものです。
サーバー側内部ドライバについては、現在INSERT
文などのSQL文の操作に4000バイトという制限があります。この制限はPL/SQL文には適用されません。INSERT
文については、次のようにPL/SQLブロック内にラップするという簡単な回避方法があります。
BEGIN INSERT id, c INTO clob_tab VALUES(?,?); END;
大量のデータに対する次のような入力モードの自動切替えは留意する必要があります。
SQL文の場合
データが2000バイトを超える場合は、setBytes
がsetBinaryStream
に切り替わります。
データが32766文字を超える場合は、setString
がsetCharacterStream
に切り替わります。
PL/SQL文
データが2000バイトを超える場合は、setBytes
がsetBinaryStream
に切り替わり、32766バイトを超える場合は、setBytesForBlob
に切り替わります。
文字列データがデータベースのキャラクタ・セット32766文字を超える場合は、setString
がsetStringForClob
に切り替わります。
setNClob
またはsetObject
は、大きな各国語キャラクタ・セット型データに使用されます。setObject
メソッドが使用される場合、ターゲット・データ型をTypes.NCHAR
、Types.NCLOB
、Types.NVARCHAR
またはTypes.LONGNVARCHAR
として設定する必要があります。
これは一部のプログラムに影響を与えます。以前は、それらのプログラムで32766文字を超えるString
値にsetString
を使用しようとするとORA-17157
エラーが発生していました。現在は、ターゲット・パラメータの型に応じて、アプリケーションの実行中にエラーが発生する場合と、操作が成功する場合があります。
もう1つの影響は、自動切替えの結果、パラメータの型の変更に適合させるために追加のサーバー側解析が実行される場合があることです。その結果、文が繰り返し実行されてデータ・サイズが制限の上下に変動すると、パフォーマンスに影響が生じます。ストリーム・モードへの切替えはバッチ処理にも影響を与えます。
Oracle Database 10gリリース1(10.1)にはSetBigStringTryClob
接続プロパティがあります。このプロパティを設定すると、データが大量の場合に、標準setString
メソッドがsetStringForClob
メソッドに切り替えられます。このプロパティは使用されなくなり、不要です。setBytesForBlob
メソッドとsetStringForClob
メソッドはテンポラリLOBを作成します。文が実行されるか、実行前に文を閉じると、テンポラリLOBが自動的に解放されます。
ただし、PL/SQLプロシージャまたはファンクションがSQL文に埋め込まれている場合、4KB未満のデータは標準であるString
としてバインドされます。4KBより大きいデータの場合は、他のSQL文と同様にドライバがデータをString
としてバインドします。これによりエラーが発生します。回避策としては、setString
またはsetStringForClob
のかわりに、setClob
またはsetCharacterStream
を使用します。さらに、コール可能文も作成できます。
出力
ResultSet
およびCallableStatement
のgetBytes
、getBinaryStream
、getSting
、getCharacterStream
およびgetAsciiStream
メソッドは、BLOB
、CLOB
およびBFILE
列またはOUT
パラメータと連携するよう拡張されています。これらのメソッドは、2147483648未満の長さの任意のLOBに対して機能します。これは完全にクライアント側で動作し、サポートされる任意のバージョンのデータベース、つまりOracle Database 8.1.7以降と連携します。
BLOB
、BFILE
またはCLOB
データの読取りおよび書込みには、LONG RAW
およびLONG
データと同じストリーミング・メカニズムを使用することもできます。読み取るには、列に対してdefineColumnType(nn, Types.LONGVARBINARY)
またはdefineColumnType(nn,Types.LONGVARCHAR)
を使用します。これによって、ダイレクト・ストリームがデータに対してLONG RAW
またはLONG
列であるかのように作成されます。この技術はOracle Database 10gリリース1(10.1)以降に限定されます。
CallableSatementとIN OUTパラメータ
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 Virtual Machine(JVM)ベンダーが提供する情報を参照して、大量のデータ要素がメモリー管理に与える影響を理解し、かわりにストリーム・インタフェースを使用することを検討してください。
テンポラリLOBは、一時データの格納に使用できます。データは、通常の表領域ではなく、一時表領域に格納されます。不要になったテンポラリLOBは解放する必要があります。解放しない場合、LOBによって使用されている一時表領域は再生されません。
テンポラリLOBは、表に挿入できます。挿入すると、LOBの永続的なコピーが作成されて格納されます。テンポラリLOBを挿入する方が便利な場合があります。たとえば、LOBデータが相対的に小さい場合は、空のロケータを取り出すデータベース・ラウンドトリップのコストに比べて、データをコピーするオーバーヘッドが小さくなります。データは、最初はサーバーの一時表領域に格納され、その後永続記憶域に移動されるためです。
テンポラリLOBは、static
メソッドcreateTemporary(Connection, boolean, int)
を使用して作成します。このメソッドは、oracle.sql.BLOB
クラスとoracle.sql.CLOB
クラスの両方に定義されています。テンポラリLOBを解放するには、freeTemporary
メソッドを使用します。
public static BLOB createTemporary(Connection conn, boolean isCached, int duration); public static CLOB createTemporary(Connection conn, boolean isCached, int duration);
引数のdurationには、oracle.sql.BLOB
クラスまたはoracle.sql.CLOB
クラスで定義されているDURATION_SESSION
またはDURATION_CALL
を使用する必要があります。クライアント・アプリケーションの場合は、DURATION_SESSION
が適しています。Javaストアド・プロシージャの場合は、DURATION_SESSION
またはDURATION_CALL
のいずれか適している方を使用できます。
isTemporary
メソッドをコールすることで、LOBがテンポラリLOBかどうかをテストできます。LOBがcreateTemporary
メソッドをコールして作成された場合、isTemporary
メソッドは、true
を戻し、それ以外の場合はfalse
を戻します。
テンポラリLOBを解放するには、freeTemporary
メソッドをコールします。セッションまたはコールを終了する前に、テンポラリLOBを解放してください。そうしないと、テンポラリLOBによって使用されている記憶域は再生されません。
注意:
|
JDK 1.5でのテンポラリNCLOBの作成
各国語キャラクタ・ラージ・オブジェクト(NCLOB)はcreateTemporary
メソッドの変種を使用して作成します。
CLOB.createTemporary (Connection conn, boolean cache, int duration, short form);
form
引数は、作成されるLOBがCLOBであるかNCLOBであるかを指定します。form
がoracle.jdbc.OraclePreparedStatement.FORM_NCHAR
の場合、メソッドはNCLOBを作成します。form
がoracle.jdbc.OraclePreparedStatement.FORM_CHAR
の場合、メソッドはCLOBを作成します。
JDK 1.6でのテンポラリNCLOBの作成
JDBC 4.0ではNCLOBが直接サポートされています。java.sql.Connection
インタフェースの標準のファクトリ・メソッドを使用してNCLOBを作成することができます。
LOBのオープンとクローズは必須ではありません。パフォーマンス上の理由から、LOBのオープンとクローズを選択できます。
オープンとクローズのコール操作内でLOB操作をラップしない場合、LOBを変更するたびにLOBが暗黙的にオープンおよびクローズされ、その結果、ドメイン索引に関するトリガーが起動します。この場合、LOBを変更するとただちに、LOBのドメイン索引がすべて更新されることに注意してください。したがって、ドメインLOB索引は常に有効となり、いつでも使用できます。
オープンとクローズのコール操作内でLOB操作をラップした場合、LOBを変更するたびにトリガーが起動することはありません。かわりに、クローズがコールされた時点で、ドメイン索引に関するトリガーが起動します。たとえば、close
メソッドをコールするまでドメイン索引が更新されないようにアプリケーションを設計できます。ただし、この場合、オープン・コールからクローズ・コールまでの間、LOBのドメイン索引は有効ではなくなります。
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例外が発生します。
注意: トランザクションでオープンしたすべてのLOBをクローズする前に、そのトランザクションをコミットしようとすると、エラーが発生します。オープンしているLOBのオープン状態は破棄され、トランザクションは正常にコミットされます。このため、トランザクション内でLOBおよび非LOBデータに対して行われた変更はすべてコミットされますが、ドメイン索引に関するトリガーは確実には実行されません。 |
この項では、ファイル・ロケータを使用してBFILEにデータを読み取る方法を説明します。この項には、次の項目が含まれます。
データベースからBFILEロケータを取り出すとき、またはデータベースにBFILEロケータを渡すときには、getterおよびsetterメソッドを使用します。
BFILEロケータの取出し
標準JDBC結果セットまたはBFILEロケータを含むコール可能文オブジェクトがある場合は、標準結果セットの
getObject
メソッドを使用して、ロケータにアクセスできます。このメソッドは、oracle.sql.BFILE
オブジェクトを返します。
また、結果セットをOracleResultSet
にキャストするか、コール可能文をOracleCallableStatement
にキャストし、getOracleObject
またはgetBFILE
メソッドを使用することにより、ロケータにアクセスすることもできます。
注意:
|
例: 結果セットからのBFILEロケータの取出し
BFILEロケータbfile_col
用の列を1つ備えたbfile_table
という表がデータベースにあるものとします。この例では、Statement
オブジェクトstmt
をすでに作成してあるものとします。
BFILEロケータを選択し、標準結果セット内にselectします。次のように、結果セットをOracleResultSet
にキャストすると、getBFILE
を使用してBFILEロケータを取り出せます。
// Select the BFILE locator into a result set ResultSet rs = stmt.executeQuery("SELECT bfile_col FROM bfile_table"); while (rs.next()) { oracle.sql.BFILE my_bfile = ((OracleResultSet)rs).getBFILE(1); }
別の方法として、getObject
を使用してBFILEロケータを戻すこともできます。この場合、getObject
はjava.lang.Object
を戻すため、結果をBFILE
にキャストしてください。たとえば、次のようになります。
oracle.sql.BFILE my_bfile = (BFILE)rs.getObject(1);
例: コール可能文からのBFILEロケータの取出し
BFILE
出力パラメータを持つ関数func
をコールする、OracleCallableStatement
オブジェクトocs
があるとします。次のコード例は、コール可能文を設定し、出力パラメータをOracleTypes.BFILE
として登録し、文を実行し、BFILEロケータを取り出します。
OracleCallableStatement ocs = (OracleCallableStatement)conn.prepareCall("{? = call func()}"); ocs.registerOutParameter(1, OracleTypes.BFILE); ocs.execute(); oracle.sql.BFILE bfile = ocs.getBFILE(1);
BFILEロケータの引渡し
BFILEロケータをプリコンパイルされたSQL文またはコール可能文に渡すには、次のどちらかの方法を使用します。
これらのメソッドは、パラメータ索引およびoracle.sql.BFILE
オブジェクトを入力として取ります。
例: BFILEロケータのプリコンパイルされたSQL文への引渡し
BFILEロケータを表に挿入するとき、表にデータを挿入するOraclePreparedStatement
オブジェクトops
があるとします。最初の列は文字列で、2番目の列はBFILEです。また、有効なoracle.sql.BFILE
オブジェクトbfile
があります。この場合は、次のように、BFILEをデータベースに書き込みます。
OraclePreparedStatement ops = (OraclePreparedStatement)conn.prepareStatement ("INSERT INTO my_bfile_table VALUES (?,?)"); ops.setString(1,"one"); ops.setBFILE(2, bfile); ops.execute();
例: BFILEロケータのコール可能文への引渡し
BFILEロケータをコール可能文に渡す方法は、プリコンパイルされたSQL文に渡す方法と同じです。この例では、BFILEロケータはmyGetFileLength
プロシージャに渡され、このプロシージャがBFILEの長さを数値で戻します。
OracleCallableStatement cstmt = (OracleCallableStatement)conn.prepareCall ("begin ? := myGetFileLength (?); end;"); try { cstmt.registerOutParameter (1, Types.NUMERIC); cstmt.setBFILE (2, bfile); cstmt.execute (); return cstmt.getLong (1); }
BFILEデータを読み取るには、最初に、BFILEロケータを取り出す必要があります。ロケータは、コール可能文からも結果セットからも取出し可能です。ロケータを取り出すと、BFILEをオープンせずに、BFILEに対して多数のメソッドをコールできます。たとえば、
oracle.sql.BFILE
メソッドfileExists()
やisFileOpen()
を使用して、BFILEがあるかどうか、オープンしているかどうかを判断できます。ただし、データの読取りおよび操作を行うには、次のようにBFILEをオープンし、クローズする必要があります。
oracle.sql.BFILE
クラスのopenFile
メソッドを使用して、BFILEをオープンします。
完了後、BFILE
クラスのcloseFile
メソッドを使用します。
BFILEデータは、Javaストリームを使用して読み取られます。BFILEから読み取るには、oracle.sql.BFILE
オブジェクトのgetBinaryStream
メソッドを使用し、入力ストリームとしてファイル全体にアクセスします。これにより、java.io.InputStream
オブジェクトが戻されます。
InputStream
オブジェクトの場合と同様に、オーバーロードされたread
メソッドの1つを使用してファイル・データを読み取り、完了時にclose
メソッドを使用します。
注意:
|
例: BFILEデータの読取り
次の例では、oracle.sql.BFILE
オブジェクトのgetBinaryStream
メソッドを使用して、BFILEデータをバイト・ストリームに読み取り、その後バイト・ストリームをバイト配列に読み取ります。この例では、BFILEがすでにオープンされているものとします。
// Read BFILE data from a BFILE locator Inputstream in = bfile.getBinaryStream(); byte[] byte_array = new byte{10}; int byte_read = in.read(byte_array);
この項では、SQL操作を使用して表にBFILE
列を作成し、BFILEの格納場所を指定する方法を説明します。この項で示す例では、Connection
オブジェクトconn
およびStatement
オブジェクトstmt
は、すでに作成してあるものとします。
新しい表でのBFILE列の作成
BFILEデータを操作するには、表内にBFILE
列を作成してから、BFILEの格納場所を指定します。BFILEの格納場所を指定するには、SQL CREATE DIRECTORY
...AS
文を使用してBFILEの存在するディレクトリの別名を指定します。この例では、ディレクトリの別名はtest_dir
で、BFILEの格納場所は/home/work
ディレクトリです。
String cmd; cmd = "CREATE DIRECTORY test_dir AS '/home/work'"; stmt.execute (cmd);
SQL CREATE
TABLE
文を使用して、BFILE
列を含む表を作成します。この例の場合、表の名前はmy_bfile_table
です。
// Create a table containing a BFILE field cmd = "CREATE TABLE my_bfile_table (x varchar2 (30), b bfile)"; stmt.execute (cmd);
この例では、VARCHAR2
列は行番号を示し、BFILE
列にはBFILEデータのロケータが格納されます。
BFILE列のデータ移入
SQL INSERT INTO...VALUES
文を使用してVARCHAR2
およびBFILE
フィールドにデータを移入します。BFILE
列には、BFILEデータを指すロケータが移入されます。BFILE
列にデータを移入するには、bfilename
関数を使用してディレクトリの別名およびBFILEのファイル名を指定します。
cmd ="INSERT INTO my_bfile_table VALUES ('one', bfilename(test_dir, 'file1.data'))"; stmt.execute (cmd); cmd ="INSERT INTO my_bfile_table VALUES ('two', bfilename(test_dir, 'jdbcTest.data'))"; stmt.execute (cmd);
この例では、ディレクトリの別名はtest_dir
です。BFILE file1.data
のロケータは、行one
のBFILE
列にロードされます。BFILE
jdbcTest.data
のロケータは、行two
のbfile
列にロードされます。
別の方法として、この時点で行番号用の行およびBFILEロケータを作成し、ロケータの挿入は後で行うこともできます。この場合は、行番号を表に挿入し、BFILEロケータのプレースホルダとしてnull
を挿入します。
cmd ="INSERT INTO my_bfile_table VALUES ('three', null)"; stmt.execute(cmd);
この例では、three
が行番号列に挿入され、プレースホルダとしてnull
が挿入されます。プログラムの後半で、プリコンパイルされたSQL文を使用してBFILEロケータを表に挿入します。
まず、有効なBFILEロケータを取出して、bfile
オブジェクトに挿入します。
rs = stmt.executeQuery("SELECT b FROM my_bfile_table WHERE x='two'"); rs.next(); oracle.sql.BFILE bfile = ((OracleResultSet)rs).getBFILE(1);
その後、プリコンパイルされたSQL文を作成します。この例ではsetBFILE
メソッドを使用してBFILEを識別しているため、次のようにプリコンパイルされたSQL文をOraclePreparedStatement
にキャストする必要があります。
OraclePreparedStatement ops = (OraclePreparedStatement)conn.prepareStatement (UPDATE my_bfile_table SET b=? WHERE x = 'three'); ops.setBFILE(1, bfile); ops.execute();
これで、行two
と行three
には、同じBFILEが格納されます。
表の中で使用可能なBFILEロケータの準備が完了すると、BFILEデータへのアクセスおよび操作が可能になります。
表の中にBFILEロケータを配置すると、ロケータの指すデータへのアクセスと操作が可能になります。データへのアクセスおよび操作を行うには、まず結果セットまたはコール可能文からロケータを選択する必要があります。
次のコードは前項の例から続いています。表の行two
からBFILEのロケータを取り出し、結果セットに挿入します。結果セットをOracleResultSet
にキャストして、結果セットに対してoracle.sql.*
メソッドを使用可能にします。BFILEに適用されるメソッドには、getDirAlias
およびgetName
のように、BFILEのオープンが不要なものもあります。読取り、長さの取出し、表示など、BFILEデータを操作するメソッドでは、BFILEをオープンする必要があります。
BFILEデータの操作完了時には、BFILEをクローズする必要があります。
// select the bfile locator cmd = "SELECT * FROM my_bfile_table WHERE x = 'two'"; rset = stmt.executeQuery (cmd); if (rset.next ()) BFILE bfile = ((OracleResultSet)rset).getBFILE (2); // for these methods, you do not have to open the bfile println("getDirAlias() = " + bfile.getDirAlias()); println("getName() = " + bfile.getName()); println("fileExists() = " + bfile.fileExists()); println("isFileOpen() = " + bfile.isFileOpen()); // now open the bfile to get the data bfile.openFile(); // get the BFILE data as a binary stream InputStream in = bfile.getBinaryStream(); int length ; // read the bfile data in 6-byte chunks byte[] buf = new byte[6]; while ((length = in.read(buf)) != -1) { // append and display the bfile data in 6-byte chunks StringBuffer sb = new StringBuffer(length); for (int i=0; i<length; i++) sb.append( (char)buf[i] ); System.out.println(sb.toString()); } // we are done working with the input stream. Close it. in.close(); // we are done working with the BFILE. Close it. bfile.closeFile();
Oracle Database 11gリリース1(11.1)では、LOB用に完全に設計し直された記憶域であるOracle SecureFileにより、次の機能が提供されています。
SecureFile圧縮により、データを圧縮してディスク容量を節約できます。
SecureFile暗号化では、暗号化されたデータのランダムな読取りおよび書込みを可能にする新しい暗号化ツールが導入されました。
重複では、Oracle Databaseの重複LOBデータが自動検出され、データを1部のみ保存することで容量が節約されます。
LOBデータ・パス最適化には、記憶域層上での論理キャッシュ、読取りプリフェッチ、新しいキャッシュ・モード、ベクトルIOなどが含まれます。
高いパフォーマンスの容量管理。
これらの機能はデータベースに実装されており、既存のAPIを使用してJDBCプログラムで透過的に使用できます。
新しいsetLobOptions
およびgetLobOptions
APIについては『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』を参照してください。コール可能文を使用してJDBCからアクセスすることもできます。
関連項目: 『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』 |