解决java插入clob字段报错问题

目录

异常剪辑

异常场景

解决方式

1.自定义类型处理类

2.使用方式 


异常剪辑

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>

在使用 `exp` 命令导出 Oracle 数据库时,如果存在 CLOB 类型的字段,可能会出现报错的情况。这是因为 `exp` 命令默认使用 `varchar2` 类型来处理 CLOB 字段,而 `varchar2` 类型的长度有限制,无法处理过长的 CLOB 字段解决这个问题有两种方法: 1. 使用 `expdp` 命令导出数据:`expdp` 命令是 Oracle 数据库的数据泵工具,它可以更好地处理 CLOB 类型的数据。使用 `expdp` 命令导出数据时,需要指定 `CLOB` 类型的列使用二进制格式导出,例如: ``` expdp user/password@database tables=table_name directory=dir dumpfile=file_name.dmp lob_as_segment=y ``` 其中,`lob_as_segment=y` 表示将 `CLOB` 类型的列以二进制格式导出。 2. 修改 `exp` 命令的参数:可以通过修改 `exp` 命令的参数来解决 CLOB 字段报错问题。具体操作如下: 1. 在 `exp` 命令中添加 `-c` 参数,表示以字符格式导出数据。 2. 在 `exp` 命令中添加 `-lob` 参数,表示导出 CLOB 字段。 3. 修改 `NLS_LANG` 环境变量,将其设为 `AMERICAN_AMERICA.AL32UTF8`,表示使用 UTF-8 编码。 示例命令如下: ``` exp user/password@database tables=table_name file=file_name.dmp log=log_name.log rows=yes compress=no direct=no indexes=no triggers=no constraints=no grants=no feedback=1000000 buffer=1000000 consistent=y commit=y statistics=none object_consistent=y recordlength=65535 consistent=y full=y rows=y constraints=n indexes=n grants=n triggers=n feedback=1000000 buffer=1000000 file=file_name.dmp log=log_name.log compress=n consistent=y direct=n rows=y statistics=none file_size=unlimited consistent=y file_name_convert=old_dir:new_dir -c -lob -NLS_LANG=AMERICAN_AMERICA.AL32UTF8 ``` 注意,修改 `NLS_LANG` 环境变量可能会影响其他程序的运行,需要谨慎操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值