clob mybatis_mybatis 解决Druid设置Oracle的Clob字段时的小坑详解

本文详细介绍了在使用Druid作为数据库连接池时,遇到的Oracle Clob字段插入和更新数据的问题。通过分析,发现由于Druid对Clob的代理处理和Oracle的强转导致的问题,并提供了相应的解决方案,包括使用`ClobProcessor`类来处理Clob对象,以及在MyBatis中避免指定jdbcType。同时提到了MyBatis中Clob类型的潜在问题和处理策略。
摘要由CSDN通过智能技术生成

http://blog.csdn.net/renfufei/article/details/44887371

mybatis 插入读取clob类型,之前使用类型转换器的方式,但是不好使,不能读取,

javaType = "java.lang.String" typeHandler ="examples.service.OracleClobTypeHandler"/>

package examples.service;

import java.sql.CallableStatement;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import oracle.sql.CLOB;

import org.apache.ibatis.type.JdbcType;

import org.apache.ibatis.type.TypeHandler;

public class OracleClobTypeHandler implements TypeHandler {

public Object valueOf(String param) {

return null;

}

@Override

public Object getResult(ResultSet arg0, String arg1) throws SQLException {

CLOB clob = (CLOB) arg0.getClob(arg1);

return (clob == null || clob.length() == 0) ? null : clob.getSubString((long) 1, (int) clob.length());

}

@Override

public Object getResult(ResultSet arg0, int arg1) throws SQLException {

return null;

}

@Override

public Object getResult(CallableStatement arg0, int arg1) throws SQLException {

return null;

}

@Override

public void setParameter(PreparedStatement arg0, int arg1, Object arg2, JdbcType arg3) throws SQLException {

CLOB clob = CLOB.empty_lob();

clob.setString(1, (String) arg2);

arg0.setClob(arg1, clob);

}

}

后面看到这个帖子,

众所周知,Oracle有很多坑, 所以才有了去IOE。

在使用Druid做数据库连接池后,其实偶尔也会碰到小坑,这就是使用开源项目所必须去填平的。【如果使用不开源的产品,那就不是坑,而是陷阱了,你都不知道怎么去填坑】

用Druid连接池,通过JDBC往Oracle数据库的Clob字段插入数据,或者更新数据时,一个问题出现了。

类似于这样:

Caused by: java.lang.ClassCastException: com.alibaba.druid.proxy.jdbc.ClobProxyImpl cannot be cast to oracle.sql.CLOB

at oracle.jdbc.driver.OraclePreparedStatement.setClob(OraclePreparedStatement.java:7919)

at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_setClob(FilterChainImpl.java:2978)

at com.alibaba.druid.filter.FilterAdapter.preparedStatement_setClob(FilterAdapter.java:1178)

at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_setClob(FilterChainImpl.java:2975)

at com.alibaba.druid.filter.FilterAdapter.preparedStatement_setClob(FilterAdapter.java:1178)

at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_setClob(FilterChainImpl.java:2975)

at com.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl.setClob(PreparedStatementProxyImpl.java:255)

at com.alibaba.druid.pool.DruidPooledPreparedStatement.setClob(DruidPooledPreparedStatement.java:588)

... 63 more

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

然后, 参考网上的文章,切换成 StringReader 以后又出现了字符串过长的问题,只好断点调试找BUG了,然后发现了一个方法:

ClobProxyImpl#getRawClob()

  • 1
  • 1

那么问题来了,也解决了。 代码贴出来如下所示:

package com.cncounter.util.solution.processor;

import java.sql.Clob;

import java.sql.PreparedStatement;

import java.sql.SQLException;

public class ClobProcessor {

public static final String JDBC_TYPE_CLOB = "clob";

public boolean processSolutionType(PreparedStatement statement, int order,

String jdbcType, Object paramValue) {

boolean result = false;

if(null == statement || order < 1){

return result;

}

//

String value = "";

if(null != paramValue){

value = paramValue.toString();

}

//

try {

if(JDBC_TYPE_CLOB.trim().equalsIgnoreCase(jdbcType)){

//

Clob clob = null;

if(paramValue instanceof Clob){

clob = (Clob)paramValue;

} else {

clob = statement.getConnection().createClob();

// 从 1 开始

clob.setString(1, value);

}

// 阿里巴巴的坑

if(clob instanceof com.alibaba.druid.proxy.jdbc.ClobProxyImpl){

com.alibaba.druid.proxy.jdbc.ClobProxyImpl impl = (com.alibaba.druid.proxy.jdbc.ClobProxyImpl)clob;

clob = impl.getRawClob(); // 获取原生的这个 Clob

}

statement.setClob(order, clob);

//

// 请注意, StringReader有坑,字段超过5万或者多少之后,就报错了. 所以注释了

// MyBatis的Clob类型也是这个BUG,如果不使用Clob,直接默认String,则Mybatis不报错

//StringReader reader = new StringReader(value);

//Reader reader = clob.getCharacterStream();

// 设置输出流

//statement.setCharacterStream(order, reader, value.length());

} else {

statement.setString(order, value);

}

result = true;

} catch (SQLException e) {

throw new RuntimeException("设置["+jdbcType+"]类型出错!", e);

}

//

return result;

}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

分析了下原因,大概Druid是因为Clob有什么需要处理的,就增加了一个代理类:com.alibaba.druid.proxy.jdbc.ClobProxyImpl ; Blob就没有。

然后呢,Oracle也比较粗暴,setClob() 里面直接强转为 oracle.sql.CLOB。于是问题就出现了。

另外值得一提的是MyBatis的Clob类型有BUG,在上面的代码注释之中也提醒了,属于是 StringReader 的坑,反正谁用谁知道。 我们的处理策略是, 在 xml 之中不指定 jdbcType,由MyBatis自己判断,当成String处理就不报错,然后也就不管了。

日期: 2015年04月05日

把clob直接配置成varchar,插入和读取都没有问题,测试过10万字节的数据,可以正常插入和读取

gggLONG NULL,    之前对应longvarchar

hhhCLOB NULL    之前对应clob

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值