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

MySQL正常执行的SQL在Spring Boot HSQL单元测试中触发BadSqlGrammarException

解决HSQL单元测试时MySQL风格DELETE JOIN语法报错的问题

嗨,我之前也遇到过一模一样的问题!你代码里的doProessing方法用的是MySQL特有的多表DELETE语法,手动测试时用的应该是MySQL或者其他兼容这种语法的数据库,所以运行正常,但HSQLDB(Spring Boot默认的测试内存数据库)并不支持这种写法,这就是抛出异常的原因。

问题根源

你写的DELETE语句是MySQL风格的:

String sql = "DELETE BS FROM FOO.TABLE1 BS JOIN FOO.TABLE2 BM on BM.SURR_KEY = BS.SURR_KEY WHERE BM.NAME = ?";

HSQLDB遵循ANSI SQL标准,不支持这种DELETE 别名 FROM 表 别名 JOIN ...的写法,它只认可标准的单表DELETE或者结合子查询的删除方式。

解决方案一:改用HSQL支持的通用SQL语法

把原SQL改成用子查询替换JOIN的方式,既兼容HSQL,也能在MySQL等主流数据库上正常运行:

String sql = "DELETE FROM FOO.TABLE1 BS WHERE BS.SURR_KEY IN (SELECT BM.SURR_KEY FROM FOO.TABLE2 BM WHERE BM.NAME = ?)";

这种写法是ANSI SQL标准,几乎所有关系型数据库都支持,通用性更强。

解决方案二:换成H2数据库并开启MySQL兼容模式

如果不想修改SQL,可以把单元测试用的数据库换成H2,并配置它模拟MySQL的语法规则:

  1. 先在pom.xml(Maven)里引入H2依赖:
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>test</scope>
</dependency>
  1. 在测试环境配置文件(比如src/test/resources/application-test.properties)里添加H2配置:
spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL;DB_CLOSE_DELAY=-1
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

这样H2会完全模拟MySQL的语法,你原来的DELETE JOIN语句就能正常执行了。

补充:测试数据初始化建议

不管用哪种方案,记得在测试前初始化对应的测试数据,确保测试场景和生产一致。比如用@BeforeEach注解插入测试记录:

@SpringBootTest
@Transactional
class ProcessingServiceTest {

    @Autowired
    private ProcessingService processingService;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @BeforeEach
    void setUpTestData() {
        // 先插入TABLE2的关联记录
        jdbcTemplate.update("INSERT INTO FOO.TABLE2 (SURR_KEY, NAME) VALUES (1, 'TEST_NAME')");
        // 插入TABLE1的待删除记录
        jdbcTemplate.update("INSERT INTO FOO.TABLE1 (SURR_KEY) VALUES (1)");
    }

    @Test
    void doProcessing_ShouldDeleteMatchingRecords() {
        int affectedRows = processingService.doProessing("test_name");
        // 验证删除了1条记录
        assertEquals(1, affectedRows);
        
        // 确认TABLE1里的关联记录已被删除
        Integer remainingCount = jdbcTemplate.queryForObject(
            "SELECT COUNT(*) FROM FOO.TABLE1 WHERE SURR_KEY = 1", 
            Integer.class
        );
        assertEquals(0, remainingCount);
    }
}

这样调整后,你的单元测试应该就能正常通过了~

内容的提问来源于stack exchange,提问作者brain storm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 07:04:21