写点什么

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

作者:YashanDB
  • 2025-02-11
    广东
  • 本文字数:2957 字

    阅读完需:约 10 分钟

本文内容来自 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 主要依赖


<dependency>


<groupId>com.yashandb</groupId>


<artifactId>yashandb-jdbc</artifactId>


<version>1.6.1</version>


<scope>runtime</scope>


</dependency>


<dependency>


<groupId>com.alibaba</groupId>


<artifactId>druid</artifactId>


<version>1.2.20</version>


</dependency>


主要代码


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

发布于: 刚刚阅读数: 5
用户头像

YashanDB

关注

全自研国产新型大数据管理系统 2022-02-15 加入

还未添加个人简介

评论

发布
暂无评论
【YashanDB知识库】共享超过32000字节字符串插入CLOB类型方案_数据库_YashanDB_InfoQ写作社区