You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot+JDBC执行多SQL语句报错及循环Bean问题排查

问题描述

我正在开发一个基于MySQL的Spring Boot应用,用JDBC操作数据。遇到两个问题:

  • 当create_table.sql里有多条SQL语句时,会触发SQL语法错误,还引发循环Bean错误
  • 只放单条语句时没问题,但如果数据库里没有对应表,单条语句也会触发Bean循环错误
触发错误的DAO方法
@PostConstruct
public void createTables() {
    try (InputStream script = new ClassPathResource("create_table.sql").getInputStream()) {
        jdbcTemplate.execute(new String(script.readAllBytes()));
    } catch (IOException e) {
        throw new RuntimeException("Failed to execute create_table.sql script", e);
    }
}
报错信息
Caused by: org.springframework.jdbc.BadSqlGrammarException: StatementCallback; bad SQL grammar [CREATE TABLE IF NOT EXISTS counter_data (
    id bigint NOT NULL AUTO_INCREMENT,
    timeStamp varchar(150) NOT NULL,
    counter_1 int,
    counter_2 int,
    counter_3 int,
    counter_4 int,
    counter_5 int,
    counter_6 int,
    counter_7 int,
    counter_8 int,
    PRIMARY KEY (id)
);
--
-- CREATE TABLE IF NOT EXISTS molding_data (
--     id bigint NOT NULL AUTO_INCREMENT,
--     timeStamp varchar(150) NOT NULL,
--     counter_1 int,
--     counter_2 int,
--     counter_3 int,
--     counter_4 int,
--     counter_5 int,
--     counter_6 int,
--     counter_7 int,
--     counter_8 int,
--     PRIMARY KEY (id)
--     );

CREATE TABLE IF NOT EXISTS production_data (
     id bigint NOT NULL AUTO_INCREMENT,
     timeStamp varchar(150) NOT NULL,
     total_production int,
     PRIMARY KEY (id)
     );
-- CREATE TABLE IF NOT EXISTS shift_data (
--     id bigint NOT NULL AUTO_INCREMENT,
--     timeStamp varchar(150) NOT NULL,
--     shift_production int,
--     PRIMARY KEY (id)
--     );]
    at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:103) ~[spring-jdbc-6.1.2.jar:6.1.2]
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:107) ~[spring-jdbc-6.1.2.jar:6.1.2]
    at org.springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1548) ~[spring-jdbc-6.1.2.jar:6.1.2]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:408) ~[spring-jdbc-6.1.2.jar:6.1.2]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:444) ~[spring-jdbc-6.1.2.jar:6.1.2]
    at io.xdoto.dao.impl.DataDaoImpl.createTables(DataDaoImpl.java:34) ~[classes/:na]
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:578) ~[na:na]
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMethod.invoke(InitDestroyAnnotationBeanPostProcessor.java:457) ~[spring-beans-6.1.2.jar:6.1.2]
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:401) ~[spring-beans-6.1.2.jar:6.1.2]
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:219) ~[spring-beans-6.1.2.jar:6.1.2]
    ... 46 common frames omitted
Caused by: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CREATE TABLE IF NOT EXISTS production_data (
     id bigint NOT NULL AUTO_INCRE' at line 29
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:121) ~[mysql-connector-j-8.1.0.jar:8.1.0]
    at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) ~[mysql-connector-j-8.1.0.jar:8.1.0]
    at com.mysql.cj.jdbc.StatementImpl.executeInternal(StatementImpl.java:763) ~[mysql-connector-j-8.1.0.jar:8.1.0]
    at com.mysql.cj.jdbc.StatementImpl.execute(StatementImpl.java:648) ~[mysql-connector-j-8.1.0.jar:8.1.0]
    at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) ~[HikariCP-5.0.1.jar:na]
    at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) ~[HikariCP-5.0.1.jar:na]
    at org.springframework.jdbc.core.JdbcTemplate$1ExecuteStatementCallback.doInStatement(JdbcTemplate.java:435) ~[spring-jdbc-6.1.2.jar:6.1.2]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:393) ~[spring-jdbc-6.1.2.jar:6.1.2]
    ... 53 common frames omitted
解决方案

1. 解决多SQL语句执行问题

JdbcTemplate.execute(String)默认不支持执行多条SQL语句,直接拼接执行会触发语法错误。改用Spring提供的ResourceDatabasePopulator或ScriptUtils工具类,它们能自动解析脚本中的分号分隔符、忽略注释,正确执行每条语句:

修改后的DAO方法示例:

@PostConstruct
public void createTables() {
    try {
        ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
        populator.addScript(new ClassPathResource("create_table.sql"));
        populator.execute(jdbcTemplate.getDataSource());
    } catch (Exception e) {
        throw new RuntimeException("Failed to execute create_table.sql script", e);
    }
}

2. 解决Bean循环依赖问题

@PostConstruct阶段Spring容器未完成所有Bean初始化,此时执行数据库操作容易引发循环依赖。建议把表初始化逻辑移到容器完全启动后执行,比如使用ApplicationRunner:

@Component
public class TableInitializer implements ApplicationRunner {

    private final JdbcTemplate jdbcTemplate;

    public TableInitializer(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
        populator.addScript(new ClassPathResource("create_table.sql"));
        populator.execute(jdbcTemplate.getDataSource());
    }
}

3. 额外建议

  • 确保create_table.sql中每条语句结尾的分号不遗漏
  • 开启MySQL日志,方便排查SQL执行细节
  • 生产环境推荐用Flyway或Liquibase这类数据库迁移工具管理表结构,比手动执行脚本更可靠

内容的提问来源于stack exchange,提问作者malith shehan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 13:35:58