iBATIS作为一个易于易用的orm(sql mapping)工具,已经广泛应用在国内的大量的项目中,成熟的iBATIS2已经为社区服务了三年之久,在iBATIS2.3.0中已经废弃了其自带的DAO的框架,转而推荐Spring 提供的ibatis support dao框架,从而得到所有依赖注入,bean管理和template以及声明式事务带来的好处。
本文就在使用过程中Spring DAO + iBATIS + Oracle Clob(Blob)存取时的一些问题的经验总结。
一、开发、测试环境描述
SUN JDK1.4.2
eclipse3.2.1
tomcat 5.0.28
spring-2.0.5.jar
ibatis-2.3.0.677.jar
ojdbc14-10.2.0.3.jar(thin)
commons-dbcp链接池
二、布署环境描述
IBM WebSphere 6.0.2.17
三、数据库描述
Oracle 10.2.0.2.0
采用thin模式连接
四、使用iBATIS自带的clobTypeHanle
读取:将clob字段对应的domain属性配置为String,不需做任何配置
insert,update,时不时出现问题,后采用变态方法,将clob字段移到insert语句的最后,将clob字段移到update的最前位置,问题解决,采用的内联的parametermap
<insert id="insertNews" parameterClass="newsForm">
<selectKey resultClass="long" keyProperty="id">select mmt_seq.nextval as id from dualselectKey>
insert into mmt_news_main(
id,
title,
info_source,
mod_index,
craft_index,
p_index,
p_name,
lang_type,
title_short,
title_deck,
brief,
add_date,
content
)values(
#id#,
#title#,
#info_source#,
#mod_index#,
#craft_index#,
#p_index#,
#p_name#,
#lang_type#,
#title_short#,
#title_deck#,
#brief#,
sysdate,
#content,javaType=java.lang.String,jdbcType=CLOB#
)
]]>
</insert>
<update id="updateNews" parameterClass="newsForm">
update mmt_news_main set
content=#content,javaType=java.lang.String,jdbcType=CLOB#,
mod_index=#mod_index#,
craft_index=#craft_index#,
p_index=#p_index#,
p_name=#p_name#,
lang_type=#lang_type#,
title=#title#,
info_source=#info_source#,
title_short=#title_short#,
title_deck=#title_deck#,
brief=#brief#
where id=#id#
]]>
<update>
但没有测试过多个clob字段的情况,不存在4000字符的问题。
注意,在插入语句中clob字段的java类型为java.io.StringReader
五、使用spring自带的OracleLobHandler
看了一下spring的源码中的注释
位置:org.springframework.jdbc.support.lob.OracleLobHandler
/**
* 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.
*
* @author Juergen Hoeller
* @since 04.12.2003
* @see #setNativeJdbcExtractor
* @see oracle.sql.BLOB
* @see oracle.sql.CLOB
*/
大体的意思是:oracle使用私有的API产生oracle.sql.BLOB和oracle.sql.CLOB实例,oracle只接受其自己API产生的实例,并且在PreparedStatement中不支持大的数据流。
此实现类需要一个原生的可以被转换成oracle.jdbc.OracleConnection的链接,所以在使用连接池的时候,就需要一个原生JDBC的转换器。
原来如此,马上配置, 快速搞定,在测试,生产环境中都没有问题,sqlMap也不需要注意clob字段的位置,以下是配置:
1、sqlMapConfig
xml 代码
- <!---->xml version="1.0" encoding="UTF-8"?>
- <!---->
- PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
- "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
-
- <sqlMapConfig>
- <settings cacheModelsEnabled="true" enhancementEnabled="true" lazyLoadingEnabled="true"
- useStatementNamespaces="false" statementCachingEnabled="true" classInfoCacheEnabled="true" />
-
- <typeHandler jdbcType="BLOB" javaType="[B"
- callback="org.springframework.orm.ibatis.support.BlobByteArrayTypeHandler" />
- <typeHandler jdbcType="CLOB" javaType="java.lang.String"
- callback="org.springframework.orm.ibatis.support.ClobStringTypeHandler" />
-
- <sqlMap resource="com/xx/ssi/dao/ibatis/maps/SysModule.xml" />
-
- sqlMapConfig>
2、spring配置(部分)
xml 代码
- <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/dsmmt" />
-
-
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- bean>
-
-
-
-
- <bean id="nativeJdbcExtractor" class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"
- lazy-init="true" />
-
-
-
-
- <bean id="oracleLobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true">
- <property name="nativeJdbcExtractor">
- <ref local="nativeJdbcExtractor" />
- property>
- bean>
-
-
- <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
- <property name="configLocation" value="classpath:com/ahtec/ssi/config/ibatis/sql-map-config.xml" />
- <property name="dataSource" ref="dataSource" />
- <property name="lobHandler">
- <ref local="oracleLobHandler" />
- property>
- bean>
在发布环境中,要将nativeJdbcExtractor 换成 org.springframework.jdbc.support.nativejdbc.WebSphereNativeJdbcExtractor
留意log4j日志,此时的clob字段的java类型为oracle.sql.Clob
Spring内置提供的NativeJdbcExtractor转换器有:
C3P0NativeJdbcExtractor
CommonsDbcpNativeJdbcExtractor
JBossNativeJdbcExtractor
NativeJdbcExtractor
NativeJdbcExtractorAdapter
SimpleNativeJdbcExtractor
WebLogicNativeJdbcExtractor
WebSphereNativeJdbcExtractor
XAPoolNativeJdbcExtractor
基本上够用了。
位于org\springframework\jdbc\support\nativejdbc下
六、最后也总结一下:
ibatis 2.0.9 + (最新的是iBATIS-2.3.0.667)
oracle 10g driver + (最新的是ojdbc14-10.2.0.3.jar)
使用spring 提供的dao框架,按如上配置,不同的链接池采用不同的NativeJdbcExtractor
不需要写显式的parameterMap(我测试了也没有成功),简洁好用的inline-parameterMap应该是首选,配合abator等自动化工具,ibatis照样能达到快速开发。
以上文字为原创,并在所述环境中测试成功,若有不妥或未尽之处,请批正。