Forums: Open Discussion (Thread #33795)

BlobInputStreamTypeHandlerを利用したINSERT処理でエラー (2013-04-03 13:42 by Anonymous #68012)

お世話になります。

「TERASOLUNA Server Framework for Java WEB」2.0.1.0を利用しております。

BLOBカラムにFileInputStreamでバイナリデータを
typeHandler("jp.terasoluna.fw.orm.ibatis.support.BlobInputStreamTypeHandler")を利用して
INSERTしようとした際にエラーが発生します。(エラー内容は後述)

context.xmlのDataSourceにfactoryで"org.apache.tomcat.jdbc.pool.DataSourceFactory"を指定することで
なんとかエラーは解消したのですが、原因がよくわからず質問をさせて頂きました。
何か参考になるような情報を頂ければ幸いです。
(※元々は、DataSourceにfactoryの記述はしておらずtomcat5.5を利用している際は何もエラーは発生していませんでした。)

よろしくお願いします。

利用環境は以下のとおりです。
【eclipse】pleiades 4.2
【java】1.7
【AP】Tomcat 7.0
【DB】oracle10g

以下エラー内容
ERROR:[]: jp.terasoluna.fw.web.struts.action.RequestProcessorEx : javax.servlet.ServletException: org.springframework.jdbc.UncategorizedSQLException: SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [0];
--- The error occurred in sqlMap.xml.
--- The error occurred while applying a parameter map.
--- Check the SQL00.xxMap.
--- Check the parameter mapping for the 'xxObject' property.
--- Cause: org.springframework.dao.InvalidDataAccessApiUsageException: OracleLobCreator needs to work on [oracle.jdbc.OracleConnection], not on [org.apache.tomcat.dbcp.dbcp.PoolableConnection]: specify a corresponding NativeJdbcExtractor; nested exception is java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.PoolableConnection cannot be cast to oracle.jdbc.OracleConnection; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:
--- The error occurred in sqlMap.xml.
--- The error occurred while applying a parameter map.
--- Check the SQL00.xxMap.
--- Check the parameter mapping for the 'xxObject' property.
--- Cause: org.springframework.dao.InvalidDataAccessApiUsageException: OracleLobCreator needs to work on [oracle.jdbc.OracleConnection], not on [org.apache.tomcat.dbcp.dbcp.PoolableConnection]: specify a corresponding NativeJdbcExtractor; nested exception is java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.PoolableConnection cannot be cast to oracle.jdbc.OracleConnection
at org.apache.struts.action.RequestProcessor.processException(RequestProcessor.java:535)
at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:433)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:236)
at jp.terasoluna.fw.web.struts.action.RequestProcessorEx.process(RequestProcessorEx.java:149)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1196)
at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:749)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:487)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:412)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:339)
at org.apache.struts.action.RequestProcessor.doForward(RequestProcessor.java:1085)
at org.apache.struts.action.RequestProcessor.processForwardConfig(RequestProcessor.java:398)
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:241)
at jp.terasoluna.fw.web.struts.action.RequestProcessorEx.process(RequestProcessorEx.java:149)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1196)
at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at jp.terasoluna.fw.web.thin.AuthenticationControlFilter.doFilter(AuthenticationControlFilter.java:226)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at jp.co.nttdata.inet.fw.ResponseExchangeFilter.doFilter(ResponseExchangeFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)
Caused by: org.springframework.jdbc.UncategorizedSQLException: SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [0];
--- The error occurred in sqlMap.xml.
--- The error occurred while applying a parameter map.
--- Check the SQL00.xxMap.
--- Check the parameter mapping for the 'xxObject' property.
--- Cause: org.springframework.dao.InvalidDataAccessApiUsageException: OracleLobCreator needs to work on [oracle.jdbc.OracleConnection], not on [org.apache.tomcat.dbcp.dbcp.PoolableConnection]: specify a corresponding NativeJdbcExtractor; nested exception is java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.PoolableConnection cannot be cast to oracle.jdbc.OracleConnection; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:
--- The error occurred in sqlMap.xml.
--- The error occurred while applying a parameter map.
--- Check the SQL00.xxMap.
--- Check the parameter mapping for the 'xxObject' property.
--- Cause: org.springframework.dao.InvalidDataAccessApiUsageException: OracleLobCreator needs to work on [oracle.jdbc.OracleConnection], not on [org.apache.tomcat.dbcp.dbcp.PoolableConnection]: specify a corresponding NativeJdbcExtractor; nested exception is java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.PoolableConnection cannot be cast to oracle.jdbc.OracleConnection
at org.springframework.jdbc.support.SQLStateSQLExceptionTranslator.translate(SQLStateSQLExceptionTranslator.java:121)
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.translate(SQLErrorCodeSQLExceptionTranslator.java:322)
at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:212)
at org.springframework.orm.ibatis.SqlMapClientTemplate.update(SqlMapClientTemplate.java:411)
at jp.terasoluna.fw.dao.ibatis.UpdateDAOiBatisImpl.execute(UpdateDAOiBatisImpl.java:189)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:301)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy5.execute(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:301)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy20.execute(Unknown Source)
at jp.terasoluna.fw.web.struts.actions.AbstractBLogicAction.doExecute(AbstractBLogicAction.java:263)
at jp.terasoluna.fw.web.struts.actions.ActionEx.execute(ActionEx.java:220)
at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:431)
... 45 more
Caused by: com.ibatis.common.jdbc.exception.NestedSQLException:
--- The error occurred in sqlMap.xml.
--- The error occurred while applying a parameter map.
--- Check the SQL00.xxMap.
--- Check the parameter mapping for the 'xxObject' property.
--- Cause: org.springframework.dao.InvalidDataAccessApiUsageException: OracleLobCreator needs to work on [oracle.jdbc.OracleConnection], not on [org.apache.tomcat.dbcp.dbcp.PoolableConnection]: specify a corresponding NativeJdbcExtractor; nested exception is java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.PoolableConnection cannot be cast to oracle.jdbc.OracleConnection
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeUpdate(GeneralStatement.java:94)
at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.update(SqlMapExecutorDelegate.java:505)
at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.update(SqlMapSessionImpl.java:90)
at org.springframework.orm.ibatis.SqlMapClientTemplate$10.doInSqlMapClient(SqlMapClientTemplate.java:413)
at org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:209)
... 84 more
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: OracleLobCreator needs to work on [oracle.jdbc.OracleConnection], not on [org.apache.tomcat.dbcp.dbcp.PoolableConnection]: specify a corresponding NativeJdbcExtractor; nested exception is java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.PoolableConnection cannot be cast to oracle.jdbc.OracleConnection
at org.springframework.jdbc.support.lob.OracleLobHandler$OracleLobCreator.createLob(OracleLobHandler.java:357)
at org.springframework.jdbc.support.lob.OracleLobHandler$OracleLobCreator.setBlobAsBinaryStream(OracleLobHandler.java:243)
at jp.terasoluna.fw.orm.ibatis.support.BlobInputStreamTypeHandler.setParameterInternal(BlobInputStreamTypeHandler.java:153)
at org.springframework.orm.ibatis.support.AbstractLobTypeHandler.setParameter(AbstractLobTypeHandler.java:100)
at com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMap.setParameter(BasicParameterMap.java:165)
at com.ibatis.sqlmap.engine.mapping.parameter.BasicParameterMap.setParameters(BasicParameterMap.java:125)
at com.ibatis.sqlmap.engine.execution.SqlExecutor.executeUpdate(SqlExecutor.java:79)
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteUpdate(GeneralStatement.java:200)
at com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeUpdate(GeneralStatement.java:78)
... 88 more
Caused by: java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.PoolableConnection cannot be cast to oracle.jdbc.OracleConnection
at oracle.sql.BLOB.createTemporary(BLOB.java:587)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.jdbc.support.lob.OracleLobHandler$OracleLobCreator.prepareLob(OracleLobHandler.java:393)
at org.springframework.jdbc.support.lob.OracleLobHandler$OracleLobCreator.createLob(OracleLobHandler.java:340)
... 96 more

Reply to #68012×

You can not use Wiki syntax
You are not logged in. To discriminate your posts from the rest, you need to pick a nickname. (The uniqueness of nickname is not reserved. It is possible that someone else could use the exactly same nickname. If you want assurance of your identity, you are recommended to login before posting.) Login

RE: BlobInputStreamTypeHandlerを利用したINSERT処理でエラー (2013-04-03 16:15 by taromaru #68014)

発生したエラーの原因は、コネクションプールと、OracleLobHandlerにDIしたNativeJdbcExtractorの組み合わせの問題です。

Tomcatのバージョンを上げてこの問題に遭遇した場合は、
通常、OracleLobHandlerにDIするNativeJdbcExtractorを、
SimpleNativeJdbcExtractorからCommonsDbcpNativeJdbcExtractorに変更することで解決します。
(この解決方法とorg.apache.tomcat.jdbc.pool.DataSourceFactoryの併用は不可です。)

解決方法によって、Tomcat5.5のときから何が変わるのかが異なります。
context.xmlを修正せずにNativeJdbcExtractorの変更で解決するのは、コネクションプールのバージョンアップ(commons-dbcpの1.2.xから1.3への変更)にあたり、
対して、
context.xmlのDataSourceにfactoryで"org.apache.tomcat.jdbc.pool.DataSourceFactory"を指定して解決するのは、コネクションプールのプロダクトの変更(commons-dbcpからTomcat JDBC Poolへの変更)にあたります。
コネクションプールのプロダクトの実績を重視するならば、前者の対応をとることになりますし、
Tomcat JDBC Pool特有の機能を使用するのであれば、後者の対応をとることになります。

以下、詳細です。

OracleLobHandlerは、
OracleのJDBCドライバのコネクション(oracle.jdbc.OracleConnectionインタフェース実装クラス)のAPIを使用して、
Lobのハンドリングを行うため、
コネクションプールから取得したコネクション(closeするとコネクションがプールに返るしくみが実装されている、コネクションのラッパ)から、ドライバのコネクションを取得する必要があります。
これを行うのが、NativeJdbcExtractor(Springのインタフェース)の実装クラスです。

SimpleNativeJdbcExtractor(NativeJdbcExtractorの実装クラスの1つ)は、
「だいたいこうすればJDBCドライバのコネクションが取得できる」という、
簡単かつ、特定のコネクションプールを意識しない実装がされており、実際には、
Connection#getMetaDataでDatabaseMetaDataを取得し、
さらに、
DatabaseMetaData#getConnectionで(うまくいけばJDBCドライバの)コネクションを取得します。
factoryに"org.apache.tomcat.jdbc.pool.DataSourceFactory"を指定してエラーが無くなったのは、
Tomcat JDBC Pool(デフォルトで使用されるcommons-dbcpとは全く別の実装)が
SimpleNativeJdbcExtractorと組み合わせてもうまくいく実装だったからです。

commons-dbcp(Tomcatでデフォルトで使用される)でも、バージョン1.2.xまではこの方法が使用できましたが、
commons-dbcp-1.3からはこの方法が利用できなくなっています。

対して、CommonsDbcpNativeJdbcExtractor(NativeJdbcExtractorの実装クラスの1つ)は、
commons-dbcpにターゲットを絞り、commons-dbcpのコネクションのラッパのAPI(getInnermostDelegateメソッド)を使用して、
JDBCドライバのコネクションを取得します。
この方法は、commons-dbcp-1.3以降でも使用可能です。

Tomcatは、どこかのバージョンで、使用するcommons-dbcpを1.2.xから1.3に変更しており、
SimpleNativeJdbcExtractorでは対応できないコネクションプールになっているため、
デフォルト設定でcommons-dbcpを使用し続ける場合は、
SimpleNativeJdbcExtractorの代わりにCommonsDbcpNativeJdbcExtractorを使用する必要があります。

類似の事象が、
https://issues.apache.org/jira/browse/DBCP-349
にもあります。
Reply to #68012

Reply to #68014×

You can not use Wiki syntax
You are not logged in. To discriminate your posts from the rest, you need to pick a nickname. (The uniqueness of nickname is not reserved. It is possible that someone else could use the exactly same nickname. If you want assurance of your identity, you are recommended to login before posting.) Login

RE: BlobInputStreamTypeHandlerを利用したINSERT処理でエラー (2013-04-03 16:56 by Anonymous #68015)

詳細な回答ありがとうございます。
とてもよくわかりすっきりできました。

実際にCommonsDbcpNativeJdbcExtractorを使用してもエラーが発生しないことも確認できましたので
どちらの解決方法をとるか検討したいと思うのですが、もう1点追加でご質問させてください。

>(この解決方法とorg.apache.tomcat.jdbc.pool.DataSourceFactoryの併用は不可です。)
と、併用は不要ではなく、不可とのことですが実際に併用して動作させてもエラーは発生致しませんでした。

併用した際に、何か問題が発生する可能性などはあるのでしょうか??
Reply to #68012

Reply to #68015×

You can not use Wiki syntax
You are not logged in. To discriminate your posts from the rest, you need to pick a nickname. (The uniqueness of nickname is not reserved. It is possible that someone else could use the exactly same nickname. If you want assurance of your identity, you are recommended to login before posting.) Login

RE: BlobInputStreamTypeHandlerを利用したINSERT処理でエラー (2013-04-03 17:45 by taromaru #68016)

> 併用した際に、何か問題が発生する可能性などはあるのでしょうか??
CommonsDbcpNativeJdbcExtractorはあくまでcommons-dbcp用に実装されているため、
それ以外のコネクションプールとの組み合わせは、そもそもクラスの実装の前提と異なることを懸念してのものです。

併用すると絶対に問題が発生するというわけではありません。

なお、commons-dbcpでないのに、CommonsDbcpNativeJdbcExtractorで動作するケースというのは、
・偶然、getInnermostDelegateというメソッドがあり、その仕様がcommons-dbcpと同じであるケース
・SimpleNativeJdbcExtractorでも構わないケース
であり、
特に後者(TOMCAT JDBC Poolはこちら)は、
DatabaseMetaData云々のロジックは、共通のスーパークラスNativeJdbcExtractorAdapterの実装によるものであるため、
結果としては動くのでしょうが、
CommonsDbcpNativeJdbcExtractor特有のロジック側は、
常に、無謀なラップ解除に挑み毎回失敗するという無駄なことをやってしまいます。

つまり、機能的な観点で結果を見る限りは問題ないのですが、
性能的な観点では、やらなくてよいこと(しかも「やらない」という選択肢がある)をやるので問題です。
(「要改善」レベルの問題だと思いますが。)
Reply to #68015

Reply to #68016×

You can not use Wiki syntax
You are not logged in. To discriminate your posts from the rest, you need to pick a nickname. (The uniqueness of nickname is not reserved. It is possible that someone else could use the exactly same nickname. If you want assurance of your identity, you are recommended to login before posting.) Login

RE: BlobInputStreamTypeHandlerを利用したINSERT処理でエラー (2013-04-03 18:13 by Anonymous #68017)

ご回答ありがとうございました。
併用しない形で検討してみます。
Reply to #68016

Reply to #68017×

You can not use Wiki syntax
You are not logged in. To discriminate your posts from the rest, you need to pick a nickname. (The uniqueness of nickname is not reserved. It is possible that someone else could use the exactly same nickname. If you want assurance of your identity, you are recommended to login before posting.) Login