clob mybatis_mybatis 解决Druid设置Oracle的Clob字段时的小坑详解
http://blog.csdn.net/renfufei/article/details/44887371mybatis 插入读取clob类型,之前使用类型转换器的方式,但是不好使,不能读取,javaType = "java.lang.String"typeHandler ="examples.service.OracleClobTypeHandler"/>package exampl..
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
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐



所有评论(0)