iBATIS操作CLOB字段实战浅析
创始人
2024-04-16 05:21:13
0

iBATIS操作CLOB字段的问题:在网上搜索发现有人遇到了相似的问题,但是情况不尽相同。现在把经验写出来,与大家分享。

环境:

JDK/JRE:1.5.0;Spring:1.2.7;iBATIS:2.1.7;Oracle:9.2.0.1;JDBC:OJDBC14_10g.jar

目标:

基于Spring提供的DBCP,使用iBATIS SQL Maps更新数据库的CLOB字段。

现象:

总是有少部分特定的数据没有更新,且并不是因为数据过长而失败,有时很短的数据也会失败。现象可以重现。原来的SQL的 Maps配置文件如下:

  1. ﹤update id="updateByFoodID" parameterClass="Food"﹥  
  2.   update TB_FOOD  
  3.     ﹤dynamic prepend="set"﹥  
  4.       ﹤isNotNull prepend="," property="foodDesc"﹥  
  5.         FOOD_DESC = #foodDesc#  
  6.       ﹤/isNotNull﹥  
  7.       ﹤isNotNull prepend="," property="foodImage"﹥  
  8.         FOOD_IMAGE = #foodImage#  
  9.       ﹤/isNotNull﹥  
  10.     ﹤/dynamic﹥  
  11.   where FOOD_ID = #foodID#  
  12. ﹤/update﹥ 

查看log4j的DEBUG输出,只有Preparing Statement、Executing Statement、和Parameters,并没有异常输出。

iBATIS操作CLOB字段初步分析原因,有如下6个:

1、首先还是怀疑有地方数据过长;

2、操作的长字符串是JSON格式的,并且数据内容可能包含‘?’、‘/’等特殊字符;

3、由于有多个程序同时使用该表,可能是事务隔离的原因;

4、LOB字段在Dynamic Mapped Statements中运行的问题;

5、这个版本的Spring对iBATIS的支持问题;

6、JDBC的版本问题。

iBATIS操作CLOB字段分别分析:

1、VARCHAR2类型的列最长为4000字节,VARCHAR2类型的PL/SQL变量最长为32767字节,操作的数据确实有可能超过64k,但程序中没有使用VARCHAR2变量存储数据,LOB类型的列更是可以存储4G的数据;

2、走查更新失败的字符串内容,没有发现特殊之处;

3、新建一张临时表,用以进行insert和update操作,发现并没有解决问题;

4、去掉动态部分,写最简单的SQL语句,也没有解决问题;

5、(暂时略过);

6、这个可能性比较小,一直都在用***版本的JDBC。

网上有人提到3种办法,其中“第2种”,给SqlMapClientFactoryBean增加lobHandler属性,据称是指能工作在native的驱动方式下,经查Spring的API文档,并不准确,摘录文档如下:

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.

因此,修改Spring配置文件:

  1. ﹤bean id="jdbcExtractor" class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor" /﹥  
  2. ﹤bean id="oracleLobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true"﹥  
  3.     ﹤property name="nativeJdbcExtractor"﹥﹤ref local="jdbcExtractor" /﹥﹤/property﹥  
  4. ﹤/bean﹥  
  5. ﹤bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"﹥  
  6.     ﹤property name="configLocation" value="classpath:conf/sqlMapConfig.xml"﹥﹤/property﹥  
  7.     ﹤property name="dataSource"﹥﹤ref local="aeqdsDataSource" /﹥﹤/property﹥  
  8.     ﹤property name="lobHandler"﹥﹤ref local="oracleLobHandler" /﹥﹤/property﹥  
  9. ﹤/bean﹥ 

未果。

使用提到的“第3种”方法,这又有2种方式,第1种是全局性的,在SQL Maps配置文件中加入callback方法:

  1. ﹤typeHandler jdbcType="BLOB" javaType="[B" callback="org.  
  2. ringframework.orm.ibatis.support.BlobByteArrayTypeHandler" /﹥  
  3. ﹤typeHandler jdbcType="CLOB" javaType="java.lang.String"   
  4. llback="org.springframework.orm.ibatis.support.ClobStringTypeHandler" /﹥ 

第2种是在单个的属性上指定typeHandler,如果是select,就可以用:

  1. ﹤resultMap id="foodResult" class="Food"﹥  
  2.   ﹤result property="foodId" column="FOOD_ID"/﹥  
  3.   ﹤result property="foodDesc" column="FOOD_DESC" typeHandler="org.springframework.orm.ibatis.support.ClobStringTypeHandler"/﹥  
  4.   ﹤result property="foodImage" column="FOOD_IMAGE" typeHandler="org.springframework.orm.ibatis.support.BlobByteArrayTypeHandler"/﹥  
  5. ﹤/resultMap﹥ 

如果是insert或update,就可以用:

  1. ﹤update id="updateByFoodID" parameterClass="Food"﹥  
  2.   update TB_FOOD  
  3.     set FOOD_DESC = #foodDesc,handler=org.springframework.orm.ibatis.support.ClobStringTypeHandler#,  
  4.         FOOD_IMAGE = #foodImage,handler=org.springframework.orm.ibatis.support.BlobByteArrayTypeHandler#  
  5.     where FOOD_ID = #foodID#  
  6. ﹤/update﹥ 

加入这个callback或typeHandler方法后,iBATIS抱怨没见过这个标记,程序不能启动。把iBATIS升级为2.3.0,顺便也把Spring升级为2.0.2,正常启动。但是效果更差,所有数据均不能更新,且日志显示只进行了Prepare Statement,却没有执行。

死马当活马医:

  1. ﹤parameterMap id="updateByFoodIDPara" class="Food"﹥  
  2.   ﹤parameter property="foodDesc" jdbcType="CLOB" javaType="java.lang.String" /﹥  
  3.   ﹤parameter property="foodImage" jdbcType="BLOB" javaType="[B" /﹥  
  4.   ﹤parameter property="foodID" jdbcType="VARCHAR" javaType="java.lang.String" /﹥  
  5. ﹤/parameterMap﹥  
  6. ﹤update id="updateByFoodID" parameterMap="updateByFoodIDPara"﹥  
  7.   update TB_FOOD  
  8.     set FOOD_DESC = ?, FOOD_IMAGE = ?  
  9.     where FOOD_ID = ?  
  10. ﹤/update﹥ 

依旧未果。

使出杀手锏,把update封装在一个存储过程中(其中不需要特别的事务处理),然后将SQL Maps配置文件的对应内容简简单单的修改为:

  1. ﹤procedure id="updateByFoodID" parameterClass="Food"﹥  
  2.   {call pkg_xxx.sp_xxx (#foodID#, #foodDesc#, #foodImage#)}  
  3. ﹤/procedure﹥ 

OK!

iBATIS操作CLOB字段的问题还是要在实战中多多总结,希望这篇文章对你理解iBATIS操作CLOB字段有所帮助。

【编辑推荐】

  1. iBATIS标签详解
  2. iBATIS是什么?
  3. iBATIS的优、缺点及注意事项浅谈
  4. iBATIS操作Blob与Clob浅析
  5. iBATIS读写CLOB数据浅析

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...
《非诚勿扰》红人闫凤娇被曝厕所... 【51CTO.com 综合消息360安全专家提醒说,“闫凤娇”、“非诚勿扰”已经被黑客盯上成为了“木...
2012年第四季度互联网状况报... [[71653]]  北京时间4月25日消息,据国外媒体报道,全球知名的云平台公司Akamai Te...