61 ScriptUtils 执行 sql 脚本 报错

前言

最近碰到了这样的一个问题, 程序需要执行一段 sql 脚本 

这段 sql 脚本是使用 spring-jdbc 里面的 ScriptUtils.executeSqlScript 来执行的, 然后 在程序执行的时候 却报错了 

但是 我们吧 sql 脚本拿出来, 放到其他的 客户端里面, 确实可以 正常执行的  

然后 这个 sql 脚本里面是有 两组相似的 sql 组合而成, 当我们注释掉 第二组sql, 发现 ScriptUtils.executeSqlScript 能够正常执行, 然后 当两组 sql 同事存在的情况下, ScriptUtils.executeSqlScript 就报错了 

呵呵 这里就来简单的看一下 这个情况 

 

一下调试基于 : jdk8 + spring-jdbc-5.2.3.RELEASE 

 

 

测试代码

/**
 * BatchExecuteWithNumberSymbol
 *
 * @author Jerry.X.He <[email protected]>
 * @version 1.0
 * @date 2020-07-22 11:13
 */
public class Test19ExecuteBatchWithNumberSymbol {

  // Test19ExecuteBatchWithNumberSymbol
  public static void main(String[] args) throws Exception {

    String path = Tools.getTmpPath("32_batchExecute/createDb03", ".sql");
    String batchExecuteSql = Tools.getContent(path);

    String sql = batchExecuteSql.replaceAll("@@", "128");
    ByteArrayResource resource = new ByteArrayResource(sql.getBytes());
    ScriptUtils.executeSqlScript(Test18DbInfo.getJdbcTemplate().getDataSource().getConnection(),
            new EncodedResource(resource, StandardCharsets.UTF_8));

  }

}

 

当所执行的 sql 文件如下的时候, 程序正常执行 

DROP DATABASE `@@`;
CREATE DATABASE `@@`;

# 用户
CREATE TABLE IF NOT EXISTS `@@`.`user`
(
    `ID`        CHAR(36)     NOT NULL COMMENT 'ID',
    `user_name` VARCHAR(128) NOT NULL COMMENT '姓名',
    `age`       VARCHAR(128) NOT NULL COMMENT '年龄',
    PRIMARY KEY (`ID`)
) COMMENT '用户';

# 用户联系人
CREATE TABLE IF NOT EXISTS `@@`.`rlt_user_contacts`
(
    `ID`          CHAR(36) NOT NULL COMMENT 'ID',
    `user_id`     CHAR(36) NOT NULL COMMENT '用户id',
    `contacts_id` CHAR(36) NOT NULL COMMENT '联系人id',
    foreign key (user_id) references `user` (`id`) on delete cascade on update cascade
) COMMENT '用户联系人';

 

当我们了一些脚本之后, 程序执行报错 

DROP DATABASE `@@`;
CREATE DATABASE `@@`;

# 用户
CREATE TABLE IF NOT EXISTS `@@`.`user`
(
    `ID`        CHAR(36)     NOT NULL COMMENT 'ID',
    `user_name` VARCHAR(128) NOT NULL COMMENT '姓名',
    `age`       VARCHAR(128) NOT NULL COMMENT '年龄',
    PRIMARY KEY (`ID`)
) COMMENT '用户';

# 用户联系人
CREATE TABLE IF NOT EXISTS `@@`.`rlt_user_contacts`
(
    `ID`          CHAR(36) NOT NULL COMMENT 'ID',
    `user_id`     CHAR(36) NOT NULL COMMENT '用户id',
    `contacts_id` CHAR(36) NOT NULL COMMENT '联系人id',
    foreign key (user_id) references `user` (`id`) on delete cascade on update cascade
) COMMENT '用户联系人';

# 用户
CREATE TABLE IF NOT EXISTS `@@`.`user02`
(
    `ID`        CHAR(36)     NOT NULL COMMENT 'ID',
    `user_name` VARCHAR(128) NOT NULL COMMENT '姓名',
    `age`       VARCHAR(128) NOT NULL COMMENT '年龄',
    PRIMARY KEY (`ID`)
) COMMENT '用户';

CREATE TABLE IF NOT EXISTS `@@`.`rlt_user_contacts02`
(
    `ID`          CHAR(36) NOT NULL COMMENT 'ID',
    `user_id`     CHAR(36) NOT NULL COMMENT '用户id',
    `contacts_id` CHAR(36) NOT NULL COMMENT '联系人id',
    foreign key (user_id) references `user02` (`id`) on delete cascade on update cascade
) COMMENT '用户联系人';

 

程序执行报错如下 

Exception in thread "main" org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #6 of Byte array resource [resource loaded from byte array]: CREATE TABLE IF NOT EXISTS `128`.`rlt_user_contacts02` ( `ID` CHAR(36) NOT NULL COMMENT 'ID', `user_id` CHAR(36) NOT NULL COMMENT '用户id', `contacts_id` CHAR(36) NOT NULL COMMENT '联系人id', foreign key (user_id) references `user02` (`id`) on delete cascade on update cascade ) COMMENT '用户联系人'; nested exception is java.sql.SQLException: Failed to open the referenced table 'user02'
	at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:626)
	at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:534)
	at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:496)
	at com.hx.test07.Test19ExecuteBatchWithNumberSymbol.main(Test19ExecuteBatchWithNumberSymbol.java:30)
Caused by: java.sql.SQLException: Failed to open the referenced table 'user02'
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:127)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:95)
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
	at com.mysql.cj.jdbc.StatementImpl.executeInternal(StatementImpl.java:790)
	at com.mysql.cj.jdbc.StatementImpl.execute(StatementImpl.java:675)
	at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:605)
	... 3 more

 

但是如果你吧 sql 复制到 navicate 里面, 执行情况 会是这样的 

61 ScriptUtils 执行 sql 脚本 报错_第1张图片

61 ScriptUtils 执行 sql 脚本 报错_第2张图片

 

 

问题的排查

因为在前面只有一套 user, user_contacts 的表结构的时候 没有报错, 但是 当存在两套 user, user_contacts 的表结构的时候, 程序就报错了

所以 我们一直在找 第二套 user, user_contacts 的是不是有哪里写的有问题的地方?, 但是 为什么 navicat 里面能够 执行? 

经过 几次对比调试, 我看了一下 生成的数据库里面, 我发现 只有 一套 user, user_contacts 的表结构的场景下面, 虽然 程序没有报错, 但是 对应的表 也没有生成 

然后 我怀疑是 这上面的 "#" 的问题, 是不是 因为 注释符号有什么影响, 呵呵 然后 吧注释符号换成了 "--", 之后 发现 程序正常执行了, 一套 user, user_contacts, 还是 两套 user, user_contacts 都得到了 期望的结果 

但是 明明 mysql 里面是支持 两种注释的方式的 "#" 或者 "--", 为什么 这里执行 会有问题呢 ? 

 

 

来到ScriptUtils

61 ScriptUtils 执行 sql 脚本 报错_第3张图片

可以看到 这里吧 sql 文件中的 sql 解析成了 6句 sql 

然后 第 2, 3, 4 句 sql 都是 "#" 开头的(注释) 

所以 第四句执行之后 没有创建表 user02, 第五句执行的时候 依赖 user02 报错了 

当然 这个结果 也解释了 为什么 只有一套 user, user_contacts 的情况 执行没有报错, 但是 数据库中并没有创建出表 

 

我们再来看一下 当注释符号为 "--" 的时候的场景 

修改上面的 createDb03.sql 里面的 "#" 为 "--", 调试情况如下, 大致可以得出的结论是 注释行被丢弃了 

61 ScriptUtils 执行 sql 脚本 报错_第4张图片

 

再来看一下 拆分语句块的逻辑, 大致如下 

上下文中传入的注释符号 只有 "--", 因此 "#" 所在行 在这里的处理不被视为注释 

然后 另外因为下面有一个 将相邻的 多个空格类字符 替换为1个 " " 的处理, 因此 "#" 到下一个 ";" 之间的语句的 ' ', '\t', '\r', '\n' 被替换为了一个 ' ', 换行符被替换成了 ' ', 传递到 mysql 服务器 发现这一整行都是 注释, 忽略执行 

61 ScriptUtils 执行 sql 脚本 报错_第5张图片

 

 

把 # 之后的换行符补回来?

我们吧 注释这一行 之后的 换行符补回来, 我们看一下 是什么效果 

61 ScriptUtils 执行 sql 脚本 报错_第6张图片

 

结果程序正常执行, 并且生成了 user02 和 user_contacts02 两张表 

 

 

完 

 

 

你可能感兴趣的:(05,问题,java,spring-jdbc,mysql)