Mybatis中使用字符串拼接方式insert到一个clob字段的方法

本文介绍了解决在Oracle数据库中插入或更新CLOB字段时出现ORA-01704错误的方法。通过使用PL/SQL块直接更新CLOB值,并提供了一种利用JDBC连接更新大量数据的有效方案。

在对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);
        }
    }

 

 

<think>好的,我现在需要解决达梦数据库CLOB字段存储字符串时出现截断的问题。根据用户提供的引用资料,字符串截断通常与字段长度设置有关,但这里涉及到CLOB类型,可能需要更深入的分析。 首先,用户提到的引用[1]和[2]指出,字符串截断可能是因为源数据库和目标数据库的字段长度不一致,例如varchar2(100)和varchar2(150)的差异。但CLOB字段设计用于存储大文本数据,理论上不应该有长度限制的问题。不过,可能是在数据迁移或插入过程中,CLOB字段的处理方式有特殊要求。 引用[3]提到在Oracle执行正常而达梦报错,可能涉及到达梦的兼容性问题。需要检查CLOB字段的存储参数,例如是否启用了以字符为单位的存储,或者字符集设置是否正确。例如,达梦的字符集如果是GB18030,而数据包含多字节字符(如UTF-8的4字节字符),可能导致计算长度时出现差异,进而引发截断。 接下来,可能的解决方案包括: 1. 检查CLOB字段的定义是否正确,是否足够大。 2. 确认达梦数据库的参数设置,如是否以字符为单位存储,字符集是否与源数据库一致。 3. 在插入数据时,使用正确的函数处理CLOB数据,如INSERT时用TO_CLOB()转换。 4. 检查应用程序是否有隐式长度限制,可能在代码中将CLOB当作VARCHAR处理,导致截断。 另外,需要查阅达梦的官方文档,确认CLOB字段的最大存储容量和配置方式。例如,达梦可能对CLOB有默认的存储限制,需要扩展表空间或调整存储参数。还可能存在事务提交的问题,未及时提交导致部分数据未写入。 最后,测试不同长度的字符串插入,观察何时出现截断,以确定具体原因。可能需要结合数据库日志和错误信息,进一步排查是字段定义、参数设置还是应用程序处理的问题。</think>### 达梦数据库CLOB字段存储字符串截断解决方案 #### 1. **检查CLOB字段定义与存储参数** - **确认字段类型和容量** CLOB字段默认容量为$2^{31}-1$字符,理论上可存储超大文本。但需检查表定义是否存在人为限制,例如: ```sql CREATE TABLE test (content CLOB STORAGE(MAXSIZE 100M)); -- 检查是否设置了不合理的大小限制 ``` - **字符集一致性** 若源数据库(如MySQL/Oracle)使用UTF-8,而达梦数据库字符集为GB18030,多字节字符可能导致长度计算差异。通过以下命令检查字符集: ```sql SELECT * FROM V$PARAMETER WHERE NAME = 'CHARSET'; -- 达梦字符集查询 ``` #### 2. **调整达梦数据库关键参数** - **启用“以字符为单位存储”** 若参数`LENGTH_IN_CHAR=0`(默认以字节为单位),可能导致UTF-8字符串被截断。修改参数为`1`(以字符为单位): ```sql ALTER SYSTEM SET 'LENGTH_IN_CHAR' = 1 SPFILE; -- 需重启生效[^1] ``` - **扩展CLOB存储空间** 达梦数据库默认表空间可能限制大对象存储。扩展表空间容量: ```sql ALTER TABLESPACE MAIN ADD DATAFILE '/dm/data/main_02.dbf' SIZE 2048; -- 根据实际路径调整 ``` #### 3. **数据写入时显式转换** - **使用`TO_CLOB()`函数** 直接插入字符串时,可能因隐式类型转换导致截断。强制转换为CLOB类型: ```sql INSERT INTO table (clob_col) VALUES (TO_CLOB('超长文本...')); ``` - **事务分批提交** 超大文本建议分段提交,避免单次事务过大: ```sql BEGIN INSERT INTO table (clob_col) VALUES (TO_CLOB('第一部分...')); COMMIT; INSERT INTO table (clob_col) VALUES (TO_CLOB('第二部分...')); COMMIT; END; ``` #### 4. **排查应用程序限制** - **检查JDBC配置** 若使用Java连接,确认`PreparedStatement`未设置`setString()`的maxLength参数,且驱动版本兼容达梦CLOB。 ```java // 错误示例:隐含长度限制 ps.setString(1, str); // 若str超过驱动默认限制可能截断 // 正确示例:使用setClob() ps.setClob(1, new StringReader(str), str.length()); ``` - **ORM框架映射** 确保Hibernate/MyBatis等框架中CLOB字段映射正确,例如: ```xml <!-- MyBatis映射 --> <result column="clob_col" property="content" jdbcType="CLOB"/> ``` #### 5. **对比源库与目标库行为** - **模拟Oracle兼容模式** 达梦提供Oracle兼容参数,开启后可能减少差异: ```sql ALTER SYSTEM SET 'COMPATIBLE_MODE' = 2; -- 开启Oracle兼容[^3] ``` - **验证数据长度计算** 通过函数`LENGTHB()`(字节长度)和`LENGTH()`(字符长度)检查数据: ```sql SELECT LENGTH(clob_col), LENGTHB(clob_col) FROM table; -- 对比源库与目标库结果 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值