前のJDBC プログラミングの基本を踏まえて、今回はJDBC 2.0の仕様であるBLOBの扱い方についてちょっと書いてみたいと思います。
最初にBLOBを扱うことのできるテーブルを作成しておきましょう。今回の例では以下のSQL文で作成しています。
CREATE TABLE BLOBTEST.BLOB (ID CHAR (10) NOT NULL WITH DEFAULT,
FILENAME VARCHAR (50) NOT NULL WITH DEFAULT,
OBJECT BLOB (2M) NOT NULL WITH DEFAULT)
一番簡単なのは 5250コマンド画面でSTRSQLコマンドを実行して、対話型SQL画面でこのコマンドを実行することでしょう。
その他、オペレーションナビゲーターの"SQLスクリプトの実行"やライブラリを指定しての"新規作成"-"テーブル"でも作成できます。
格納するバイナリーイメージを引数として受け取ってキーをつけてデータベースに格納するプログラムサンプルと、キーを引数としてそのバイナリーイメージを取り出して表示するプログラムサンプルをご紹介します。
前のJDBC プログラミングの基本と書き方はまったく同様です。
前回と同じく、システム名(=ホスト名)に"S1234567"、ユーザープロファイル名に"user"、パスワードに"password"をリテラルとして使用しています。
まず引数としてファイルの名前とデータベースに格納した後のIDとなるキーを受け取ります。
// パラメータの取得(ファイル名)
String f = new String( args[0]);
// パラメータの取得(キー)
String id = new String( args[1]);
テーブルに格納する際に setBinaryStream メソッドを使用するのですが、ファイルのバイナリーストリームとその長さを引数として必要とします。
そのため、ファイルの長さとその内容のバイナリーストリームが必要になります。
// ファイルサイズの取得
File file = new File(f);
long fileLength = file.length();
int fLength = (int)fileLength;
// ファイル内容の取得
InputStream fin = new FileInputStream(f);
ここで、前回のJDBCプログラミングの基本では使用しなかったのですが、パラメーターマーカーというものを使用します。
前回の例ではSQL文はすべてリテラルでした。つまりあらかじめ決められていて変更できないようになっていたわけです。
実際には、あるデータを選択する場合はその時々で範囲が異なるのが普通でしょうし、データを新たに挿入するような場合、更新する場合、削除する場合、それぞれそのデータは異なるものでしょう。
ここでもBLOBオブジェクトを受け取って新たに格納するわけです。
つまりSQL文の一部をパラメータとして動的に作成する必要があります。そういう場合にこのパラメーターマーカーを使用します。
接続オブジェクトに対して createStatement
メソッドでステートメントオブジェクト(=SQLコンテナ)を今までの場合は作成してきましたが、パラメーターマーカーを使用する場合は
prepareStatement メソッドを使用します。
変数にしておきたいところを ? にしておきます。その後の
setBinaryStreamの最初の引数の"1"で一番目の"?"のところに値が代入されます。
stmt = con.prepareStatement("INSERT INTO BlobTest.Blob(ID,FileName,Object) VALUES('" + id + "','" + f + "',?)");
stmt.setBinaryStream(1,fin,fLength);
その後は同様に excuteUpdate メソッドを使用してSQLを実行させて、close します。
import java.sql.*; import java.io.*; class InsertBlobSample { public static void main (String args[]) { String url = "jdbc:as400://"; String system = "S1234567"; String user = "user"; String password = "password"; Connection con = null; PreparedStatement stmt =null; try { // JDBCドライバロード Class.forName("com.ibm.as400.access.AS400JDBCDriver"); // DB接続 con = DriverManager.getConnection(url + system, user,password); // パラメータの取得(ファイル名) String f = new String( args[0]); // パラメータの取得(キー) String id = new String( args[1]); // ファイルサイズの取得 File file = new File(f); long fileLength = file.length(); int fLength = (int)fileLength; // ファイル内容の取得 InputStream fin = new FileInputStream(f); stmt = con.prepareStatement("INSERT INTO BlobTest.Blob(ID,FileName,Object) VALUES('" + id + "','" + f + "',?)"); stmt.setBinaryStream(1,fin,fLength); int num = stmt.executeUpdate(); System.out.println("登録件数 : " + num); stmt.close(); } catch(SQLException e) { while(e != null) { System.err.println(e.getMessage()); System.err.println(e.getSQLState()); System.err.println(e.getErrorCode()); System.out.println(""); e = e.getNextException(); } } catch(Exception e) { e.printStackTrace(); } finally { try { con.close(); } catch(SQLException e) {} } } }
ファイルの取得からの一連の流れは以下のようにまとめられます。
File file = new File(f);
stmt = con.prepareStatement("INSERT INTO BlobTest.Blob(ID,FileName,Object) VALUES('" + id + "','" + f + "',?)");
stmt.setBinaryStream(1,new FileInputStream(file), (int)file.length());
以上の部分のみを書き直したのがこちらになります。
import java.sql.*; import java.io.*; class InsertBlobSample2 { public static void main (String args[]) { String url = "jdbc:as400://"; String system = "S1234567"; String user = "user"; String password = "password"; Connection con = null; PreparedStatement stmt =null; try { // JDBCドライバロード Class.forName("com.ibm.as400.access.AS400JDBCDriver"); // DB接続 con = DriverManager.getConnection(url + system, user,password); // パラメータの取得(ファイル名) String f = new String( args[0]); // パラメータの取得(キー) String id = new String( args[1]); // ファイルの取得 File file = new File(f); stmt = con.prepareStatement("INSERT INTO BlobTest.Blob(ID,FileName,Object) VALUES('" + id + "','" + f + "',?)"); stmt.setBinaryStream(1,new FileInputStream(file), (int)file.length()); int num = stmt.executeUpdate(); System.out.println("登録件数 : " + num); stmt.close(); } catch(SQLException e) { while(e != null) { System.err.println(e.getMessage()); System.err.println(e.getSQLState()); System.err.println(e.getErrorCode()); System.out.println(""); e = e.getNextException(); } } catch(Exception e) { e.printStackTrace(); } finally { try { con.close(); } catch(SQLException e) {} } } }
今度はBLOBの検索です。
SQLの処理は、パラメーターマーカーを使用している(=prepareStatement
メソッドを使用している)ことをのぞけば、以前のselectの例とほとんど同じです。
キーをBLOBの格納の例と同様にプログラム外部の引数としてもらって、それをもとにデータベースを検索します。
// SQLコンテナの作成
stmt = con.prepareStatement("SELECT Object FROM BlobTest.Blob WHERE id=?");
// パラメータマーカーのセット
stmt.setString(1, id);
// SQL文の実行
ResultSet rs = stmt.executeQuery();
// 検索結果取り出し
if (!rs.next()) { txt.setText("No image found"); return; }
selectの場合の常道ですが、SQLが正しく実行されたら、結果セットからの取り出しを行います。
BLOBの場合は、受け取った結果をバイナリーストリームとして受け取ってバイト列に変換します。
そのバイト列をいわゆるJavaの一般的なグラフィックのコーディングで表示させるわけです。
InputStream in = rs.getBinaryStream(1);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (true) {
int bytes = in.read(b);
if (bytes == -1) {
break;
}
baos.write(b,0,bytes);
}
b = baos.toByteArray();
import java.sql.*; import java.io.*; import javax.swing.*; import java.awt.*; import java.awt.event.*; public class SelectBlobSample extends Canvas { public Image im; public byte b[] = new byte[4096]; public static JFrame frame; public SelectBlobSample(String id) { super(); // 画面の大きさおよびバックの色の設定 setSize( 300, 300); setBackground( Color.white ); // BLOBフィールドの取得 getBlob(id); } public void paint(Graphics g) { if (im != null) g.drawImage(im, 0, 0, this); } public void getBlob(String id) { TextField txt = new TextField("",80); String url = "jdbc:as400://"; String system = "S1234567"; String user = "user"; String password = "password"; Connection con = null; PreparedStatement stmt =null; try { // JDBCドライバのロード Class.forName("com.ibm.as400.access.AS400JDBCDriver"); // DB接続の作成 con = DriverManager.getConnection(url + system, user,password); // SQLコンテナの作成 stmt = con.prepareStatement("SELECT Object FROM BlobTest.Blob WHERE id=?"); // パラメータマーカーのセット stmt.setString(1, id); // SQL文の実行 ResultSet rs = stmt.executeQuery(); // 検索結果取り出し if (!rs.next()) { txt.setText("No image found"); return; } InputStream in = rs.getBinaryStream(1); ByteArrayOutputStream baos = new ByteArrayOutputStream(); while (true) { int bytes = in.read(b); if (bytes == -1) { break; } baos.write(b,0,bytes); } b = baos.toByteArray(); // クローズ処理 in.close(); baos.close(); rs.close(); stmt.close(); } catch(SQLException e) { while(e != null) { System.err.println(e.getMessage()); System.err.println(e.getSQLState()); System.err.println(e.getErrorCode()); System.out.println(""); e = e.getNextException(); } } catch(Exception e) { e.printStackTrace(); } finally { try { con.close(); } catch(SQLException e) {} // イメージ作成 im = Toolkit.getDefaultToolkit().createImage(b); } } public static void main (String args[]) { String id = new String( args[0]); //表示用フレームの作成 frame = new JFrame("show content of Blob column"); SelectBlobSample canvas = new SelectBlobSample(id); frame.getContentPane().add( canvas, "Center" ); frame.pack(); frame.show(); //フレームの終了処理 frame.addWindowListener ( new WindowAdapter () { public void windowClosing(WindowEvent e) { frame.dispose(); System.exit(0); } } } }
BLOBのバイト列への書き出しは getBlob メソッドを使用しても同じことが行えます。
Blob aBlob = rs.getBlob(1);
byte[] b = aBlob.getBytes(1, (int)aBlob.length());
getBytes メソッドを使用して該当部分を書き換えたものがこちらになります。
import java.sql.*; import java.io.*; import javax.swing.*; import java.awt.*; import java.awt.event.*; public class SelectBlobSample2 extends Canvas { public Image im; public byte b[] = new byte[4096]; public static JFrame frame; public SelectBlobSample(String id) { super(); // 画面の大きさおよびバックの色の設定 setSize( 300, 300); setBackground( Color.white ); // BLOBフィールドの取得 getBlob(id); } public void paint(Graphics g) { if (im != null) g.drawImage(im, 0, 0, this); } public void getBlob(String id) { TextField txt = new TextField("",80); String url = "jdbc:as400://"; String system = "S1234567"; String user = "user"; String password = "password"; Connection con = null; PreparedStatement stmt =null; try { // JDBCドライバのロード Class.forName("com.ibm.as400.access.AS400JDBCDriver"); // DB接続の作成 con = DriverManager.getConnection(url + system, user,password); // SQLコンテナの作成 stmt = con.prepareStatement("SELECT Object FROM BlobTest.Blob WHERE id=?"); // パラメータマーカーのセット stmt.setString(1, id); // SQL文の実行 ResultSet rs = stmt.executeQuery(); // 検索結果取り出し if (!rs.next()) { txt.setText("No image found"); return; } Blob aBlob = rs.getBlob(1); byte[] b = aBlob.getBytes(1, (int)aBlob.length()); // クローズ処理 rs.close(); stmt.close(); } catch(SQLException e) { while(e != null) { System.err.println(e.getMessage()); System.err.println(e.getSQLState()); System.err.println(e.getErrorCode()); System.out.println(""); e = e.getNextException(); } } catch(Exception e) { e.printStackTrace(); } finally { try { con.close(); } catch(SQLException e) {} // イメージ作成 im = Toolkit.getDefaultToolkit().createImage(b); } } public static void main (String args[]) { String id = new String( args[0]); //表示用フレームの作成 frame = new JFrame("show content of Blob column"); SelectBlobSample canvas = new SelectBlobSample(id); frame.getContentPane().add( canvas, "Center" ); frame.pack(); frame.show(); //フレームの終了処理 frame.addWindowListener ( new WindowAdapter () { public void windowClosing(WindowEvent e) { frame.dispose(); System.exit(0); } } } }
それぞれ実行するとこんなかんじになります。
> C:\JDBCSAMPLE>java InsertBlobSample sp_image.jpg 1
登録件数 : 1
> C:\JDBCSAMPLE>java SelectBlobSample 1