在对Oracle数据库插入或者更新CLOB字段的时候,直接拼接INSERT INTO和UPDATE语句,会报一个
ora-01704:字符串文件太长
的异常。那是因为oracle的隐式转换机制,即oracle默认把字符串转换成varchar2类型,而这个字符串的长度又比4000大,所以会报ora-01704错误。说得通俗一点,就是两个单引号之间的字符不能超过4000,但是由于业务需求我又必须使用单引号将其引起来。于是我从网上搜了很多方法,其中有用for update方法解决的。但是mybatis不知该如何获取resultset,因此此方法只能作罢。后来看到网上有使用PL/SQL的方法,我想尝试一下直接在mybatis中使用是否能跑起来,结果一试发现居然可以!……感动……泪奔。具体实现方法如下:
//单独对大字段进行更新
private void updateClobFields(String tableName,String dataId,List<Map> fieldList,RavFormInstanceMapper mapper){
for(Map field:fieldList){
StringBuffer sb=new StringBuffer();
sb .append(" DECLARE")
.append(" clobValue clob;")
.append(" BEGIN")
.append(" clobValue := '"+field.get("value")+"';")
.append(" UPDATE "+tableName+" T SET T."+field.get("column")+" = clobValue WHERE T.id='"+dataId+"';")
.append(" COMMIT;")
.append(" END;");
mapper.updateInst(sb.toString());
}
}
mapper.updateInst代码为:
@Update("${sql}")
public void updateInst(@Param(value = "sql") String sql);
后续:这个方法也有问题,超过了某一个5位数(具体忘了)之后仍然会报异常,最后只能采用单独开辟一个JDBC的连接实现。具体做法如下:
public static void updateClobFields(String tableName,String dataId,List<Map> fieldList) {
try{
//获得数据库连接
Connection con = DBAccess.getConnection();
con.setAutoCommit(false);
for(Map field:fieldList){
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("select "+field.get("column")+" from "+tableName+" where ID='"+dataId+"' for update");
Writer outputWriter=null;
if (rs.next())
{
//得到java.sql.Clob对象后强制转换为oracle.sql.CLOB
oracle.sql.CLOB clob = (oracle.sql.CLOB) rs.getClob((String)field.get("column"));
if(clob!=null){
outputWriter=clob.setCharacterStream(0l);
char[] charset = ((String) field.get("value")).toCharArray();
outputWriter.write(charset, 0, charset.length);
}else{
logger.error("CLOB类型字段:"+field.get("column")+"为null !");
}
}
if(outputWriter!=null){
outputWriter.flush();
outputWriter.close();
}
}
con.commit();
con.close();
}catch(SQLException e){
logger.error("",e);
}catch (IOException e){
logger.error("",e);
}
}