这篇文章写个那些曾经和我遇到一样的问题的朋友们:
背景描述如下:
使用Spring+hibernate+Struts(可选)作为项目架构,DB中某个字段使用了Blob或Clob字段,对应的Entity中欲使用String或byte[]类型与lob类型字段对应(对String的增删修查操作方便多了,而且可以使用hibernate的二级缓存)。
关于lob类型字段如何配置,请查看如下文章:
Spring + Hibernate + Oracle9i中使用Clob
- org.springframework.dao.InvalidDataAccessApiUsageException: OracleLobCreator needs to work on [oracle.jdbc.OracleConnection], not on [oracle.jdbc.OracleConnection$$EnhancerByProxool$$a32a8b3c]: specify a corresponding NativeJdbcExtractor; nested exception is java.lang.ClassCastException: oracle.jdbc.OracleConnection$$EnhancerByProxool$$a32a8b3c cannot be cast to oracle.jdbc.driver.OracleConnection
- at org.springframework.jdbc.support.lob.OracleLobHandler$OracleLobCreator.createLob(OracleLobHandler.java:357)
解决方案如下:
1.必选按Spring + Hibernate + Oracle9i中使用Clob提到的书写代码
2.选择合适的lob处理句柄,即根据数据库选择正确的lobHandler,关于lobHandler的描述请看下面的说明
3.选择合适的nativeJdbcExtractor,即对应DataSource的jdbc连接器,关于nativeJdbcExtractor的描述请看后面的说明
4.如果上述还没解决问题,如果你是用的oracle9i的数据库,可以尝试使用oracle10g驱动试试
如果是别的版本的数据库,尝试使用高版本的数据库驱动试试
在我的项目中,就是使用了oracle10g的驱动才得以解决问题。
关于lobHandler的一些描述:
Spring的api中指出了DefaultLobHandler这个句柄是适用于oracle10g的,而oracle9i应该使用OracleLobHandler。
(经过本人实践:10G用OracleLobHandler也可以)
DefaultLobHandler:
Default implementation of the LobHandler interface. Invokes the direct accessor methods that java.sql.ResultSet
and java.sql.PreparedStatement
offer.
This LobHandler should work for any JDBC driver that is JDBC compliant in terms of the spec's suggestions regarding simple BLOB and CLOB handling. This does not apply to Oracle 9i, and only to a limited degree to Oracle 10g! As a consequence, use OracleLobHandler for accessing Oracle BLOBs/CLOBs.
OracleLobHandler:
Default implementation of the LobHandler interface. Invokes the direct accessor methods that java.sql.ResultSet
and java.sql.PreparedStatement
offer.
LobHandler implementation for Oracle databases. Uses proprietary API to create oracle.sql.BLOB
and oracle.sql.CLOB
instances, as necessary when working with Oracle's JDBC driver. Note that this LobHandler requires Oracle JDBC driver 9i or higher!
While most databases are able to work with DefaultLobHandler, Oracle just accepts Blob/Clob instances created via its own proprietary BLOB/CLOB API, and additionally doesn't accept large streams for PreparedStatement's corresponding setter methods. Therefore, you need to use a strategy like this LobHandler implementation.
Needs to work on a native JDBC Connection, to be able to cast it to oracle.jdbc.OracleConnection
. If you pass in Connections from a connection pool (the usual case in a J2EE environment), you need to set an appropriate NativeJdbcExtractor to allow for automatical retrieval of the underlying native JDBC Connection. LobHandler and NativeJdbcExtractor are separate concerns, therefore they are represented by separate strategy interfaces.
Coded via reflection to avoid dependencies on Oracle classes. Even reads in Oracle constants via reflection because of different Oracle drivers (classes12, ojdbc14) having different constant values! As this LobHandler initializes Oracle classes on instantiation, do not define this as eager-initializing singleton if you do not want to depend on the Oracle JAR being in the class path: use "lazy-init=true" to avoid this issue.
关于nativeJdbcExtractor的一些描述:
当您在 Web 应用服务器或 Spring 中配置数据源时,从数据源中返回的数据连接对象是本地 JDBC 对象(如 DB2Connection、OracleConnection)的代理类,这是因为数据源需要改变数据连接一些原有的行为以便对其进行控制:如调用 Connection#close()
方法时,将数据连接返回到连接池中而非将其真的关闭。
在访问 LOB 数据时,根据数据库厂商的不同,可能需要使用被代理前的本地 JDBC 对象(如 DB2Connection 或 DB2ResultSet)特有的 API。为了从数据源中获取本地 JDBC 对象, Spring 定义了 org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor
接口并提供了相应的实现类。NativeJdbcExtractor
定义了从数据源中抽取本地 JDBC 对象的若干方法:
方法 | 说明 |
---|---|
Connection getNativeConnection(Connection con) | 获取本地 Connection 对象 |
Connection getNativeConnectionFromStatement(Statement stmt) | 获取本地 Statement 对象 |
PreparedStatement getNativePreparedStatement(PreparedStatement ps) | 获取本地 PreparedStatement 对象 |
ResultSet getNativeResultSet(ResultSet rs) | 获取本地 ResultSet 对象 |
CallableStatement getNativeCallableStatement(CallableStatement cs) | 获取本地 CallableStatement 对象 |
有些简单的数据源仅对 Connection
对象进行代理,这时可以直接使用 SimpleNativeJdbcExtractor
实现类。但有些数据源(如 Jakarta Commons DBCP)会对所有的 JDBC 对象进行代理,这时,就需要根据具体的情况选择适合的抽取器实现类了。下表列出了不同数据源本地 JDBC 对象抽取器的实现类:
数据源类型 | 说明 |
---|---|
WebSphere 4 及以上版本的数据源 | org.springframework.jdbc.support.nativejdbc.WebSphereNativeJdbcExtractor |
WebLogic 6.1+ 及以上版本的数据源 | org.springframework.jdbc.support.nativejdbc.WebLogicNativeJdbcExtractor |
JBoss 3.2.4 及以上版本的数据源 | org.springframework.jdbc.support.nativejdbc.JBossNativeJdbcExtractor |
C3P0 数据源 | org.springframework.jdbc.support.nativejdbc.C3P0NativeJdbcExtractor |
DBCP 数据源 | org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor |
ObjectWeb 的 XAPool 数据源 | org.springframework.jdbc.support.nativejdbc.XAPoolNativeJdbcExtractor |
摘自网上的一段话:
从网上找的,我没怎么看明白,看样子是在说类加载器的相关问题。
Comment by Juergen Hoeller [02/Oct/05 04:41 PM]
This is likely to be caused by a class loader issue: that is, the Oracle JDBC driver classes being available from multiple class loaders.
Spring's OracleLobHandler used a locally loaded OracleConnection class to check whether the given Connection handle is actually an Oracle JDBC connection. That might fail if the locally loaded OracleConnection class is not the same as the one used at the server level.
Consequently, we've relaxed that check to accept any kind of Connection handle. If a ClassCastException arises within the Oracle driver's BLOB/CLOB handling (a sign of a non-OracleConnection passed in), we throw an expressive exception that indicates to specify a correct NativeJdbcExtractor.
Essentially, it's a post-invocation check rather than a pre-invocation check now, which should avoid any potential class loader issues.
This change should be available in Monday night's nightly Spring snapshot. Please give it a try and let us know whether it works for you!
Juergen
一些参考文章:
1.Spring 让 LOB 数据操作变得简单易行
2.Struts+Spring+Hibernate浅见
3.解决websphere使用LobHandler写LOB字段的很迷惑人的错误
4.我曾经遇到的问题-请教SSH中Clob类型字段不能使用hibernate二级缓存的问题
5.Hibernate+Spring搞定Clob、Blob的存取
http://hi.baidu.com/slandi/blog/item/51badf9449c21342d0135e71.html
另外:关于blob在java里面如何处理以及spring配置文件 参考
Spring+Hibernate实现Oracle的BLOB、CLOB上传:
http://blog.sina.com.cn/s/blog_517aff8b0100d6yn.html
利用Spring MVC 上传图片文件:
http://amcucn.javaeye.com/blog/264457