【YashanDB知识库】共享超过32000字节字符串插入CLOB类型方案

简介: 本文来自YashanDB官网,介绍了解决向崖山数据库CLOB类型字段插入超过32000字节字符串时出现的YAS-04107错误的方法。通过JDBC动态变量绑定技术,实现对不同表的超长字符串插入支持。方案基于YashanDB JDBC和Druid组件,动态解析SQL语句并绑定变量,提供通用性。文章包含关键代码示例及程序使用说明,需JDK 1.8环境运行,并提供附件下载以辅助实施。

本文内容来自YashanDB官网,原文内容请见 https://www.yashandb.com/newsinfo/7508311.html?templateId=1718516

概述

超过32000字节字符串通过insert into values的方式插入崖山数据库CLOB类型字段(无论是DBeaver还是yasql),会报YAS-04107 string exceeding limit 32000错误。本文通过jdbc动态变量绑定的方案支持超过32000字节字符串插入到CLOB类型字段的表。

方案

通过jdbc变量绑定的方式可以支持超过32000字节字符串插入到CLOB类型字段的表,但是不通用,不同的表需要编写不同的插入代码,本方案使用yashandb jdbc和druid组件,动态解析插入sql的字段和字段类型,进行动态变量绑定,可以支持不同的表进行超过32000字节字符串插入到CLOB类型字段的表。

关键代码

pom主要依赖



com.yashandb

yashandb-jdbc

1.6.1

runtime



com.alibaba

druid

1.2.20

主要代码

public static void insertSql(DataSource dataSource, String sql) {

    log.info("insertSql sql = {}", sql);

 

    // 获取数据库连接

    Connection connection = getConnection(dataSource);

 

    PreparedStatement ps = null;

 

    // 通过sql获取SQLStatement

    SQLStatement stmt = InsertSqlParserUtil.getInsertStmt(sql);

 

    // 通过SQLStatement动态获取insert into xxx values(?,?,?......)插入语句

    String insertSQL = InsertSqlParserUtil.getInsertSQL(stmt);

 

    try {

        // 通过insertSQL获取PreparedStatement对象

        ps = connection.prepareStatement(insertSQL);

        // 动态绑定插入变量

        InsertSqlParserUtil.bindPreparedStatement(stmt, ps);

        // 执行插入

        ps.execute();

    } catch (SQLException e) {

        log.error("insert异常", e);

    } finally {

        closePreparedStatement(ps);

        closeConnection(connection);

    }

}

 

public static SQLStatement getInsertStmt(String sql) {

    SQLStatement stmt = null;

 

    DbType druidDbType = DbType.oracle;

 

    String formatSQL = SQLUtils.format(sql, druidDbType);

    List<SQLStatement> stmtList = new ArrayList<>();

    try {

        stmtList = SQLUtils.parseStatements(formatSQL, druidDbType);

    } catch (Exception exp) {

        log.error("parseStatements sql is :{}", formatSQL);

        log.error("parseStatements exception : {}", exp.getMessage());

    }

 

    log.info("getInsertValues param stmtList size is {}", stmtList.size());

 

    stmt = stmtList.get(0);

    SchemaStatVisitor statVisitor = SQLUtils.createSchemaStatVisitor(druidDbType);

    stmt.accept(statVisitor);

    log.info(SQLUtils.toSQLString(stmt));

 

    if (stmt instanceof OracleInsertStatement) {

        return stmt;

    }

    return stmt;

}

 

public static String getInsertSQL(SQLStatement stmt) {

    StringBuilder sb = new StringBuilder();

    String schemaName = null;

    String tableName = null;

    if (stmt instanceof OracleInsertStatement) {

        schemaName = ((OracleInsertStatement) stmt).getTableSource().getSchema();

        tableName = ((OracleInsertStatement) stmt).getTableSource().getTableName();

        if (StringUtils.isEmpty(tableName)) {

            return sb.toString();

        } else if (!StringUtils.isEmpty(schemaName)) {

            tableName = schemaName + "." + tableName;

        }

 

        if (!StringUtils.isEmpty(tableName)) {

            sb.append("INSERT INTO ").append(tableName.toUpperCase()).append(" VALUES(");

        }

 

        List<SQLExpr> values = ((OracleInsertStatement) stmt).getValuesList().get(0).getValues();

 

        for (int i = 0; i < values.size(); i++) {

            if (i == values.size() - 1) {

                sb.append("?");

            } else {

                sb.append("?,");

            }

        }

        sb.append(")");

    }

 

    return sb.toString();

}

 

public static void bindPreparedStatement(SQLStatement stmt, PreparedStatement pst) {

    List<SQLExpr> values = ((OracleInsertStatement) stmt).getValuesList().get(0).getValues();

    for (int i = 0; i < values.size(); i++) {

        SQLExpr value = values.get(i);

        try {

            if (value instanceof SQLIntegerExpr) {

                pst.setInt(i + 1, ((SQLIntegerExpr) value).getNumber().intValue());

            } else if (value instanceof SQLBigIntExpr) {

                pst.setLong(i + 1, ((SQLBigIntExpr) value).getNumber().intValue());

            } else if (value instanceof SQLNumberExpr) {

                Number number = ((SQLNumberExpr) value).getNumber();

                if (number instanceof BigDecimal) {

                    pst.setBigDecimal(i + 1, (BigDecimal) number);

                }

            } else if (value instanceof SQLCharExpr) {

                pst.setString(i + 1, ((SQLCharExpr) value).getText());

            } else if (value instanceof SQLTimestampExpr) {

                pst.setTimestamp(i + 1, Timestamp.valueOf(((SQLTimestampExpr) value).getValue()));

            } else if (value instanceof SQLDateExpr) {

                pst.setDate(i + 1, Date.valueOf(((SQLDateExpr) value).getValue()));

            } else if (value instanceof SQLDateTimeExpr) {

                pst.setDate(i + 1, Date.valueOf(((SQLDateTimeExpr) value).getValue()));

            } else if (value instanceof SQLNullExpr) {

                pst.setNull(i + 1, Types.NULL);

            } else {

                pst.setString(i + 1, ((SQLCharExpr) value).getText());

            }

        } catch (SQLException e) {

            log.error("绑定插入变量异常", e);

        }

    }

}

程序使用说明

注:需要安装jdk1.8

1、解压yashandb-sql-imp-1.0-bin.zip,然后设置yashandb-sql-imp/conf/jdbc.properties中需要导入的崖山用户连接

2、导入命令:

win:

cd yashandb-sql-imp/bin

.\yashandb-sql-imp.bat D:\clob_test

linux:

cd yashandb-sql-imp/bin

./yashandb-sql-imp.sh /data/clob_test

注:参数/data/clob_test为sql文件存放目录,支持多sql文件,但只支持执行insert into xxx values这样的插入语句

附件

yashandb-sql-imp-1.0-bin.zip

相关文章
|
11月前
|
SQL 存储 关系型数据库
【YashanDB知识库】共享从 MySQL异常处理CONTINUE HANDLER的改写方法
【YashanDB知识库】共享从 MySQL异常处理CONTINUE HANDLER的改写方法
|
10月前
|
SQL 测试技术 数据库
【YashanDB知识库】IMP跨网络导入慢问题
问题现象:290M数据,本地导入2分钟,跨机导入耗时显著增加(最高30分钟)。 原因分析:`imp`逐条SQL通过网络传输至yashanDB执行,交互频繁导致性能下降。 影响版本:客户测试环境22.2.8.3。 解决方法:将导入文件上传至与yashanDB同机后使用`imp`,减少网络延迟。 经验总结:优化`imp`工具,支持直接上传文件至服务器端执行,降低网络依赖。
|
10月前
|
监控 数据库
【YashanDB 知识库】ycm 托管数据库时报错 OM host ip:127.0.0.1 is not support join to YCM
在托管数据库时,若 OM 的 IP 被设置为 127.0.0.1,将导致无法托管至 YCM,并使数据库失去监控。此问题源于安装时修改了 OM 的监听 IP。解决方法包括:将 OM 的 IP 修改为本机实际 IP 或 0.0.0.0,同时更新 env 文件及 yasom 后台数据库中的相关配置。经验总结指出,应避免非必要的后台 IP 修改,且数据库安装需遵循规范,不使用仅限本机访问的 IP(如 127.0.0.1)。
|
10月前
|
监控 网络安全 数据库
YashanDB 知识库:ycm 纳管主机安装 YCM-AGENT 时报错 “任务提交失败,无法连接主机”
在安装 ycm-agent 纳管主机时,可能出现因端口未开放导致的报错问题。此问题会阻止 YCM 对主机和数据库的监控功能,影响版本为 `yashandb-cloud-manager-23.2.1.100-linux-aarch64.tar`。原因是目标主机(如 10.149.223.121)未开放 9070 或 9071 端口。解决方法包括关闭防火墙、添加白名单或开放指定端口,需与管理员确认操作。处理过程涉及网络检查、端口测试等步骤。端口问题解决后,若再次安装报唯一键错误,需先移除失败主机再重试。
|
10月前
|
监控 Java Shell
【YashanDB 知识库】ycm 托管数据库时,数据库非 OM 安装无法托管
本文主要介绍了因数据库未按规范使用 yasboot 安装导致的问题及解决方法。问题表现为无 yasom 和 yasagent 进程,且目录结构缺失,致使 ycm 无法托管与监控。分析发现可能是数据库版本旧或安装不规范引起。解决方法为先生成配置文件,安装 yasom 和 yasagent,再生成并修改托管配置模板,最终通过命令完成托管至 yasom 和 ycm。总结强调了按规范安装数据库的重要性以避免类似问题。
|
11月前
|
SQL 关系型数据库 MySQL
【YashanDB知识库】MySQL field 函数的改写方法
【YashanDB知识库】MySQL field 函数的改写方法
|
11月前
|
数据库
【YashanDB知识库】服务器重启后启动yasom和yasagent进程时有告警
【YashanDB知识库】服务器重启后启动yasom和yasagent进程时有告警
|
11月前
|
SQL Oracle 关系型数据库
【YashanDB知识库】共享利用Python脚本解决Oracle的SQL脚本@@用法
【YashanDB知识库】共享利用Python脚本解决Oracle的SQL脚本@@用法
|
11月前
|
数据库
【YashanDB知识库】服务器重启后启动yasom和yasagent进程时有告警
本文介绍了YashanDB在特定场景下的问题分析与解决方法。当使用yasboot重启数据库后,yasom和yasagent进程虽启动成功但出现告警,原因是缺少libnsl.so.1库文件或环境变量配置错误。解决步骤包括:检查系统中是否存在该库文件,若不存在则根据操作系统类型安装(有外网时通过yum或apt,无外网时创建符号链接),若存在则调整环境变量配置,并重新启动相关进程验证问题是否解决。
|
11月前
|
存储 关系型数据库 MySQL
【YashanDB知识库】共享从 MySQL异常处理CONTINUE HANDLER的改写方法
本文介绍了MySQL中`CONTINUE HANDLER FOR NOT FOUND`的用法及其在YashanDB中的改写方法。通过一个示例存储过程,展示了如何使用游标和异常处理机制来应对“未找到数据”的情况。在MySQL中,`CONTINUE HANDLER`用于捕获此类异常;而在YashanDB中,则需改用游标的`%NOTFOUND`属性和`NO_DATA_FOUND`异常处理。文章对比了两者的执行效果,帮助用户顺利完成从MySQL到YashanDB的业务迁移。

热门文章

最新文章