目录
异常剪辑
org.springframework.jdbc.UncategorizedSQLException
### Error updating database. Cause: java.sql.SQLException: ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值
### The error may exist in file [磁盘路径\target\classes\mapper\oracle\xxxx.xml]
### The error may involve com.gene.xxxDao.saveAll-Inline
### The error occurred while setting parameters
### SQL: insert into xxxxx ( snow_no, business_date, message_name, message_text, msg_send_status, msg_send_time, success_flag, update_time ) ( select ?, ?, ?, ?, ?, ?, ?, ? from dual UNION ALL select ?, ?, ?, ?, ?, ?, ?, ? from dual )
### Cause: java.sql.SQLException: ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值
; uncategorized SQLException for SQL []; SQL state [72000]; error code [1461]; ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值
; nested exception is java.sql.SQLException: ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值
[省略]
异常场景
我在使用mybatis批量往oracle数据库中插入数据,其中某字段在java中为String类型,Oracle中为clob类型,该字段在java中过长时会报这个错误
解决方式
1.自定义类型处理类
- 该类用于处理CLOB字段,可以自定义BLOB处理类。
- 如果想要全局配置处理CLOB字段,需要在mybatis的配置文件中注册typeHandlers,注意标签的顺序(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,plugins?,environments?,databaseIdProvider?,mappers?),否则会报错。
- setParameter(PreparedStatement arg0, int arg1, String arg2, JdbcType arg3)为插入做字段处理的关键方法,将clob当成string处理。
- 如果是查询oracle的clob字段,可以用resultMap标签来处理,同样在字段后引入typeHandler=com.xxx.OracleClobTypeHandler
- 坑1:有些网络资料会介绍使用parameterMap来处理,parameterMap已经淘汰,该方式不要用。
- 坑2:网络上大部分的代码使用 CLOB Clob = oracle.sql.CLOB.empty_lob(); empty_lob已经被淘汰了,该方法不要用
- 坑3:如果你是一个负责人的程序员,当你发现坑2的时候你可能会尝试采用该方式创建CLOB对象:CLOB.getEmptyCLOB(),该方式获取的对象中没有oracle的connection,也就是CLOB类中的getDBAccess()会抛出异常。而且Datum类的private byte[] data字段也未初始化。(这里不做源码分析了)
- 我们使用如下方式来创建CLOB对象:
Connection connection = arg0.getConnection();
OracleConnection oracleConnection = connection.unwrap(OracleConnection.class);
CLOB clob = CLOB.createTemporary(oracleConnection, true, 1, (short) 1);
处理类代码:
package com.gene.config;
import oracle.jdbc.OracleConnection;
import oracle.sql.CLOB;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import java.sql.*;
/**
* Oracle CLOB字段处理类.
* @Author: gene
**/
public class OracleClobTypeHandler implements TypeHandler<String> {
public String valueOf(String param) {
return null;
}
@Override
public String 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 String getResult(ResultSet arg0, int arg1) throws SQLException {
return null;
}
@Override
public String getResult(CallableStatement arg0, int arg1) throws SQLException {
return null;
}
@Override
public void setParameter(PreparedStatement arg0, int arg1, String arg2, JdbcType arg3) throws SQLException {
Connection connection = arg0.getConnection();
OracleConnection oracleConnection = connection.unwrap(OracleConnection.class);
CLOB clob = CLOB.createTemporary(oracleConnection, true, 1, (short) 1);
clob.setString(1, arg2);
arg0.setClob(arg1, clob);
}
}
2.使用方式
typeHandler=com.xxx.OracleClobTypeHandler
<insert id="saveAll" parameterType="java.util.List" databaseId="oracle">
<choose>
<when test="list != null and list.size > 0 ">
insert into xxxx
(
snow_no,
business_date,
message_name,
message_text,
msg_send_status,
msg_send_time,
success_flag,
update_time
)
(
<foreach collection="list" item="item" index= "index" separator=" UNION ALL ">
select
#{item.snowNo},
#{item.businessDate},
#{item.messageName},
#{item.messageText, jdbcType=CLOB, typeHandler=com.xxx.OracleClobTypeHandler},
#{item.msgSendStatus},
#{item.msgSendTime},
#{item.successFlag},
#{item.updateTime}
from dual
</foreach>
)
</when>
<otherwise>
select 0 from dual where 1 = 0
</otherwise>
</choose>
</insert>