- - PR -
OracleへJNDI接続し、BLOB型へ挿入する際に発生するクラスキャスト例外の回避法は?
1
投稿者 | 投稿内容 |
---|---|
|
投稿日時: 2006-02-23 11:52
お世話になります。
以前、似たような(というより全く同じ)状況についての質問があったようですが、 結局、DriverManager接続で逃げたとのことで、これを解決する方法を 改めてお聞きしたいと思います。 状況ですが、 1)class.forNameクラスでDriverMagager.getConnection()でDB接続した場合、OK 2)DataSourceを活用して(DataSource) Context.lookup(データソース)で接続した場合、NG となっています。 環境: WinXP Jdk1.4.2_10 Struts1.2.4 Tomcat5.0.28 Oracle9.2.0 JNDIに関するserver.xml記述は <Resource name="/jdbc/develop" type="javax.sql.DataSource"/> <ResourceParams name="/jdbc/develop"> <parameter> <name>maxWait</name> <value>5000</value> </parameter> <parameter> <name>maxActive</name> <value>100</value> </parameter> <parameter> <name>password</name> <value>dev_password</value> </parameter> <parameter> <name>url</name> <value>jdbc:oracle:thin:@devDB:1521:orcl</value> </parameter> <parameter> <name>driverClassName</name> <value>oracle.jdbc.OracleDriver</value> </parameter> <parameter> <name>maxIdle</name> <value>10</value> </parameter> <parameter> <name>username</name> <value>dev_user</value> </parameter> </ResourceParams> となっています。 そして、 1)DriverMagagerを使用して接続 Class.forName("oracle.jdbc.driver.OracleDriver"); Connection conn=DriverManager.getConnection("jdbc:oracle:thin:@devDB:1521:orcl", "dev_user", "dev_password"); としてConnectionを取得 2)DataSourceを使用してJNDI接続 Context cx = new InitialContext(); DataSource ds = (DataSource )cx.lookup("java:comp/env/jdbc/develop"); Connection conn = ds.getConnection(); としてConnectionを取得 ここまでは、書き込みミスがあるかもしれませんが、とりあえずは実環境では 接続成功し、LOB以外のSELECT/DELETE/INSERT/UPDATEは 正常に行われているとお考えください。 問題のBLOB型の挿入箇所なのですが、 (BLOB以外のINSERT処理) ↓ (INSERTしたレコードをSELECT) ↓ ResultSet rs = selStmt.executeQuery(); if (rs.next()) { try { BLOB blob = ((OracleResultSet) rs).getBLOB(1); // クラスキャスト例外発生箇所 OutputStream blobOutputStream = blob.getBinaryOutputStream(); blobOutputStream.write(imageData, 0, imageData.length); blobOutputStream.close(); conn.commit(); } catch (IOException ex) { conn.rollback(); throw new Exception(ex); } } else { throw new SQLException("BLOBの格納に失敗"); } 1)の接続の場合には問題なく成功しますが、 2)の場合は、 BLOB blob = ((OracleResultSet) rs).getBLOB(1); の部分でClassCastExceptionが発生します。 これを、以下のようにしても同様に例外が発生します。 Blob _blob = rs.getBlob(1); BLOB blob = (BLOB) _blob; // ここで例外発生 いろいろ試してみましたが、 ・ResultSet → OracleResultSet へのキャスト ・java.sql.Blob → oracle.sql.BLOB へのキャスト どちらをやっても例外が発生します。 ちなみに、 ResultSet rs = selStmt.executeQuery(); System.out.println(rs.getClass().getName()); とすると、 org.apache.commons.dbcp.DelegatingResultSet となっています。 と、ここまでは以前の相談者の方のケースと同じです。 DriverManager接続に逃げたいところですが、その為のユーザー名、パスワードを 設定ファイル等に記述するのは、セキュリティ面からNGとされているため、 どうしてもJNDI接続の方法をとらなければなりません。 JNDI接続でBLOB挿入を実現する為の解決法、いとぐち、その他なんでも結構ですので宜しくお願いいたします。 |
|
投稿日時: 2006-02-23 12:46
DBCP から受け取る ResultSet が JDBC の標準 API だけを実装したラッパオブジェクトだからでしょう。
DelegationResultSet のインターフェースを見る限り内部に保持している実際のResultSetオブジェクトを取得する方法は用意されていないようです。 商用サーバであればそういう問題もないんですが・・・ ・JDBC インタフェースのベンダ拡張機能の使い方 http://www.beasys.co.jp/e-docs/wls/docs81/jdbc/thirdparty.html#1078159 DelegationResultSet.java に書き加えて ResultSet getActualResultSet() みたいなメソッドをご自分で付け加えてはいかがでしょう? |
|
投稿日時: 2006-02-23 15:46
これが使えるのではないでしょうか。
http://jakarta.apache.org/commons/dbcp/apidocs/org/apache/commons/dbcp/DelegatingResultSet.html#getInnermostDelegate() |
|
投稿日時: 2006-02-23 21:36
以下のようなかんじで問題なくできます。
ResultSet rs = pStmt.executeQuery(); DelegatingResultSet drs = (DelegatingResultSet)rs; OracleResultSetImpl impl = (OracleResultSetImpl)drs.getDelegate(); BLOB blob = impl.getBLOB(1); OutputStream out = blob.getBinaryOutputStream(); int size = blob.getBufferSize(); byte[] buff = new byte[size]; BufferedInputStream bin = new BufferedInputStream(....); int length = -1; while ((length = bin.read(buff)) != -1) { out.write(buff, 0, length); } out.close(); bin.close(); |
|
投稿日時: 2006-02-23 21:51
ふと疑問に思ったのですが、
BLOB blob = (BLOB)rs.getBlob(); が、なぜClassCastExceptionとなるのか疑問に思いました・・・ 9.2iのclasses12.jarのOracleResultSetImplをリバースしたのですが、 getBlobメソッドはBLOBを返すgetBLOBメソッドに委譲しているだけなんですよね。 で、getBLOBメソッドで返されるBLOBのインスタンスはBlobを実装しているので、 getBlobメソッド経由ではBlob型としてしか見えませんが、 実態はBLOB型のはずなので、キャストできてもいいと思うのです。 さらに、DelegatingResultSetのgetBlobメソッドは、 独自の型でラップするわけでもなく、委譲対象の値をそのまま返しています。 何故なんでしょうか・・ 今環境がないので、詳しい人は教えてください。 |
1