Ibatis读写CLOB,BLOB数据

Ibatis是一个高效,方便,易于学习的数据访问组件,在性能上比hibernate高,学习难度也比hibernate和jdo要低,而且它比直接使用jdbc方便和易于维护。所以Ibatis深入大家的喜爱,一些对性能有更高的要求的系统(如保险,金融行业系统),或改造遗留系统时,Ibatis是数据访问组件的首选。  
在使用Oracle数据库时,读取CLOB和BLOB等大类型的数据一直是个比较犯难的事,一般都是通过JDBC代码来实现对CLOB和BLOB数据的读写,效果和性能都是最好的,但是代码也相当复杂,且代码难以重用
在使用ibatis作为数据访问组件,也经常会遇到要读取CLOB,BLOB大类型数据。怎样使用Ibatis读取CLOB,BLOB数据也是一个难题,并且Oracle在这方面一直没有解决好。
1. 测试数据库


Sql代码   复制代码   收藏代码
  1. CREATE TABLE USERINFO(USERID VARCHAR2(5),
  2. USERNAME VARCHAR2(20),
  3. MEMO CLOB,
  4. constraint PK_USERINFO primary key(USERID));
2.域模型对象


Java代码   复制代码   收藏代码
  1. import java.io.Serializable;
  2. public class UserInfoDTO implements Serializable {
  3. /*用户id*/
  4. private String userID;
  5. /*用户名*/
  6. private String userName;
  7. /*备注*/
  8. private String memo;
  9. public String getMemo() {
  10. return memo;
  11. }
  12. public void setMemo(String memo) {
  13. this.memo = memo;
  14. }
  15. public String getUserID() {
  16. return userID;
  17. }
  18. public void setUserID(String userID) {
  19. this.userID = userID;
  20. }
  21. public String getUserName() {
  22. return userName;
  23. }
  24. public void setUserName(String userName) {
  25. this.userName = userName;
  26. }
  27. }
3.数据访问对象接口

Java代码   复制代码   收藏代码
  1. public interface UserInfoDao {
  2. public List getUsers(UserInfoDTO user) throws DataAccessException;
  3. public void insertUser(UserInfoDTO user) throws DataAccessException;
  4. }
一、 读取CLOB,BLOB类型数据的几种方法
1. jdbc实现
采用jdbc来读写是最原始,也是最直接的方法
UserInfoDaoImpl.java

Java代码   复制代码   收藏代码
  1. public class UserInfoDaoImpl extends SqlMapClientDaoSupport implements
  2. UserInfoDao {
  3. Connection con = null;
  4. private Connection getConnection() throws SQLException {
  5. Connection con = null;
  6. con = this.getSqlMapClientTemplate().getDataSource().getConnection();
  7. con.setAutoCommit(false);
  8. return con;
  9. }
  10. public void insertUser(UserInfoDTO user) throws DataAccessException {
  11. try {
  12. this.con = this.getConnection();
  13. final String insertSql = "INSERT INTO USERINFO(USERID,USERName,memo) VALUES(?,?,?)";
  14. final String selectSql = "SELECT MEMO FROM USERINFO WHERE USERID = ? FOR UPDATE";
  15. final String updateSql = "UPDATE USERINFO SET MEME = ? WHERE USERID = ?";
  16. PreparedStatement ps = con.prepareStatement(insertSql);
  17. ps.setString(1, user.getUserID());
  18. ps.setString(2, user.getUserName());
  19. ps.setClob(3, CLOB.empty_lob());
  20. ps.executeUpdate();
  21. ps.close();
  22. ps = this.con.prepareStatement(selectSql);
  23. ps.setString(1, user.getUserID());
  24. ResultSet rs = ps.executeQuery();
  25. rs.next();
  26. CLOB memo = (CLOB) rs.getClob(1);
  27. memo.setString(1, user.getMemo());
  28. ps = this.con.prepareStatement(updateSql);
  29. ps.setClob(1, memo);
  30. ps.setString(2, user.getUserID());
  31. ps.executeUpdate();
  32. ps.close();
  33. this.con.commit();
  34. catch (Exception ex) {
  35. throw new DataAccessResourceFailureException(ex.getMessage(), ex);
  36. finally {
  37. try {
  38. if (this.con != null)
  39. this.con.close();
  40. catch (Exception ex) {
  41. throw new DataAccessResourceFailureException(ex.getMessage(),
  42. ex);
  43. }
  44. }
  45. }
2. 使用Spring的org.springframework.jdbc.support.lob.OracleLobHandler类处理
2.1 sql-map-config.xml的配置

Xml代码   复制代码   收藏代码
  1. <typeHandler jdbcType="CLOB" javaType="java.lang.String" callback="org.springframework.orm.ibatis.support.ClobStringTypeHandler"/>
2.2 sqlMapClient的配置

Xml代码   复制代码   收藏代码
  1. <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
  2. <property name="configLocation"><value>/sql-map-config.xml</value></property>
  3. <property name="dataSource"><ref local="dataSource"/></property>
  4. <property name="lobHandler"><ref local="oracleLobHandler"/></property>
  5. </bean>
  6. <bean id="oracleLobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler"
  7. lazy-init="true">
特别注意:采用这种方法只对数据源是直接连接Oracle 的JDBC驱动方式有效,如果你采用数据连接池作为数据源,则这种办法无效。但是一般大型的项目都是使用连接池的,所以这个方法有很大的局限性。


3. 通过实现Ibatis的TypeHandlerCallback接口来实现
下面是读取的方法:

Java代码   复制代码   收藏代码
  1. public class OracleClobTypeHandlerCallback implements TypeHandlerCallback {
  2. public void setParameter(ParameterSetter setter, Object obj)
  3. throws SQLException {
  4. // TODO Auto-generated method stub
  5. CLOB clob = CLOB.empty_lob();
  6. clob.setString(1, (String)obj);
  7. setter.setClob(clob);
  8. }
  9. public Object getResult(ResultGetter getter) throws SQLException {
  10. CLOB clob = (CLOB) getter.getClob();
  11. return (clob == null || clob.length() == 0 )? null :clob.getSubString((long)1, (int)clob.length());
  12. }
  13. public Object valueOf(String param) {
  14. // TODO Auto-generated method stub
  15. return null;
  16. }
  17. }
sqlMap 的配置

Xml代码   复制代码   收藏代码
  1. <resultMap id="userResult" class="com.prs.application.ehld.sample.common.dto.UserInfoDTO">
  2. <result property="userID" column="USERID" columnIndex="1"/>
  3. <result property="userName" column="USERNAME" columnIndex="2"/>
  4. <result property="memo" column="memo" jdbcType="CLOB" javaType = "java.lang.String" typeHandler =" OracleClobTypeHandlerCallback "/>
  5. </resultMap>
二、 存在的问题
上面三种方法都存在的问题:
1. 使用jdbc来实现,就失去了使用ibatis带来的便利,同时也失去了自动事务管理的能力,还有需要自己去手工管理连接对象。代码量也相当复杂。
2. 使用spring提供的处理器,不支持采用数据连接池的数据源,有很大的局限性。
3. 通过实现ibatis的回调接口来实现,也有一定的局限性,需要新增一个类,配置也不方便,还可能会出错。

难道ibatis读写LOB大类型数据就没辙了吗?通过试验,发现可以配置ParameterMap和ResultMap就可以方便的实现对LOB的读写了,而且不用去实现任何类。只需要配置就可以了

三、 通过配置ParameterMap和ResultMap来实现对LOB类型的读写
3.1 sqlMap的配置

Xml代码   复制代码   收藏代码
  1. <resultMap id="userResult" class="com.prs.application.ehld.sample.common.dto.UserInfoDTO">
  2. <result property="userID" column="USERID" columnIndex="1"/>
  3. <result property="userName" column="USERNAME" columnIndex="2"/>
  4. [color=darkred]<result property="memo" column="memo" jdbcType="CLOB" javaType = "java.lang.String" />[/color]</resultMap> 
  5. <parameterMap id="userPara" class = "com.prs.application.ehld.sample.common.dto.UserInfoDTO">
  6. <parameter property="userID" jdbcType="VARCHAR" javaType ="java.lang.String"/>
  7. <parameter property="userName" jdbcType="VARCHAR" javaType ="java.lang.String"/>
  8. [color=darkred]<parameter property="memo" jdbcType="CLOB" javaType ="java.lang.String"/>[/color]
  9. </parameterMap>
3.2 插入和读取语句的配置

Xml代码   复制代码   收藏代码
  1. <select id="getUserInfoList" resultMap="userResult" >
  2. SELECT
  3. USERINFO.USERID ,
  4. USERINFO.USERName ,
  5. USERINFO.MEMO
  6. FROM USERINFO
  7. </select>
  8. <insert id="insertUserInfo" parameterMap = "userPara" >
  9. INSERT INTO USERINFO(USERID,
  10. USERName,
  11. memo)
  12. VALUES([color=darkred]?,?,?[/color]
  13. )
  14. </insert>
注意:因为使用了ParameterMap作为输入参数,在插入语句中用?号来代替属性值(如:#userId#)

而不是常见的:
Xml代码   复制代码   收藏代码
  1. INSERT INTO USERINFO(USERID,
  2. USERName,
  3. memo)
  4. VALUES(#userId#,
  5. #userName#,
  6. #memo#
  7. )
但是当paramaterMap的class属性是java.util.Map类时,应该使用#userId#类似的参数,不能用?来代替。
但是这又有一个问题,就是插入的字符串不能超过4000个字符,而CLOB类型的字段可以存4GB大小的字符。只要对userInfo对象的memo成员设置字符串超过了4000个字符,就提示“不能创建更多的套接字”,为什么会报这个错,暂是没有弄清楚。

而需求是要CLOB字段要存6000个汉字,相当于12000个英文字符。可以说是白忙了一场,没有达到目的。

四、 使用Oracle 10g的jdbc驱动程序
因为字符串只要超过了4000个字符就不能插入,所以不得不试着换一下驱动程序看看。一直以来都认为oracel的jdbc 驱动对处理LOB对象有一些问题,想看看10g出来后是不是有所改变。于是上网下载10g的驱动,一阵痛苦的等待后,问题解决,我把字符串设为12万个字符也没有问题了。

另外采用10g 的驱动就算不使用parameterMap也可以成功的插入字符串到CLOB类型字段去,请要注意的是,这样只能插入的字符一定要小于32767个。也就是说我把memo 属性设置多于32766个字符,照样插不进去。这个原因主要是jdbc驱动限制了String的长度的原因。

Xml代码   复制代码   收藏代码
  1. <insert id="insertUserInfo" parameterClass = "UserInfoDTO" >
  2. INSERT INTO USERINFO(USERID,
  3. USERName,
  4. memo)
  5. VALUES(#userID#,
  6. #userName#,
  7. #memo#
  8. )
  9. </insert>
使用10g的驱动,这样能写入32766个字符

五、 怎么读写BLOB
上面都一直在说CLOB,其实把CLOB实现了,那么BLOB也同样简单,只是注意它的java类型,如果一个字段为BLOB类型,那么在parameterMap中jdbcType 为BLOB,
把javaType设为:[]byte就可以了。
例:

Xml代码   复制代码   收藏代码
  1. <parameterMap id="userPara" class = "com.prs.application.ehld.sample.common.dto.UserInfoDTO">
  2. <parameter property="userID" jdbcType="VARCHAR" javaType ="java.lang.String"/>
  3. <parameter property="userName" jdbcType="VARCHAR" javaType ="java.lang.String"/>
  4. [color=red]<parameter property="memo" jdbcType="BLOB" javaType ="[]byte"/>[/color]
  5. </parameterMap>
假设memo在数据库中为BLOB 类型  

那么在javaBean中memo的java类型为[]byte  


六、 总结  
采用10g的驱动,和通过配置parameterMap和resultMap能够轻松和完美的解决LOB大型数据的读写,无需要编写新的java来实现,也没有局限性。 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值