自定义MariaDB镜像的Testcontainers测试JDBC连接失败排查
问题分析与解决方案
核心问题定位
你的问题大概率是Spring上下文初始化时,Testcontainers启动的MariaDB容器还未完成自定义初始化脚本的执行,导致应用尝试连接时目标数据库(或默认的test库)还未就绪;而手动连接时容器已经完成所有初始化操作,因此能成功连接。
具体排查与修复步骤
1. 强制等待初始化脚本执行完毕
Testcontainers默认的健康检查仅验证MariaDB服务是否启动,不会等待docker-entrypoint-initdb.d下的自定义脚本执行完成。你需要添加自定义等待逻辑,直到目标数据库创建完成:
MariaDBContainer<?> mariaDBContainer = new MariaDBContainer<>("你的自定义镜像标签") .withUsername("test") .withPassword("test") .waitingFor(Wait.forSqlQuery("SELECT 1 FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'my_app_db'") .withUsername("test") .withPassword("test") .withDatabase("mysql") // 先连接默认的mysql系统库查询 .withTimeout(Duration.ofMinutes(2))); // 给足脚本执行时间
2. 修正数据源URL的目标库
报错URL指向的是默认test库,但你的自定义脚本创建的是my_app_events和my_app_db。如果应用需要连接这两个自定义库中的一个,直接修改URL路径:
- 例如连接
my_app_db,URL应为:
jdbc:mariadb://localhost:${容器映射端口}/my_app_db
- 在ApplicationContextInitializer中,可通过
mariaDBContainer.getJdbcUrl().replace("/test", "/my_app_db")快速替换默认库名。
3. 验证初始化脚本的正确性
确保SQL脚本无语法错误,授权语句覆盖目标库:
-- 用IF NOT EXISTS避免重复创建报错 CREATE DATABASE IF NOT EXISTS my_app_db; CREATE DATABASE IF NOT EXISTS my_app_events; -- 给test用户授予目标库的全权限 GRANT ALL PRIVILEGES ON my_app_db.* TO 'test'@'%'; GRANT ALL PRIVILEGES ON my_app_events.* TO 'test'@'%'; FLUSH PRIVILEGES; -- 刷新权限使设置立即生效
4. 确保容器启动与属性设置的顺序
在ApplicationContextInitializer中,必须等容器完全启动并就绪后,再设置数据源属性,避免注入未就绪的连接信息。
完整示例代码
public class CustomMariaDBInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { @Override public void initialize(ConfigurableApplicationContext ctx) { // 启动自定义MariaDB容器并等待初始化完成 MariaDBContainer<?> mariaDBContainer = new MariaDBContainer<>("your-custom-mariadb:latest") .withUsername("test") .withPassword("test") .waitingFor(Wait.forSqlQuery("SELECT 1 FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'my_app_db'") .withUsername("test") .withPassword("test") .withDatabase("mysql") .withTimeout(Duration.ofMinutes(2))); mariaDBContainer.start(); // 动态将容器连接信息注入Spring环境 TestPropertyValues.of( "spring.datasource.url=" + mariaDBContainer.getJdbcUrl().replace("/test", "/my_app_db"), "spring.datasource.username=" + mariaDBContainer.getUsername(), "spring.datasource.password=" + mariaDBContainer.getPassword() ).applyTo(ctx.getEnvironment()); } }
内容的提问来源于stack exchange,提问作者lrkwz
相关产品推荐
相关产品推荐

