MySQL TestContainers init-script 模式创建失败

Posted

技术标签:

【中文标题】MySQL TestContainers init-script 模式创建失败【英文标题】:MySQL TestContainers init-script Schema Creation Failing 【发布时间】:2021-03-09 21:38:04 【问题描述】:

尝试在 mysql 测试容器实例中创建架构时遇到以下问题。测试用户好像没有相应的权限?

配置:

spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver
spring.datasource.url=jdbc:tc:mysql:5.7.22:///test?TC_INITSCRIPT=component/db/init_mysql.sql
Caused by: org.testcontainers.ext.ScriptUtils$UncategorizedScriptException: Failed to execute database script from resource [create schema new_schema CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;]
    at org.testcontainers.ext.ScriptUtils.executeDatabaseScript(ScriptUtils.java:375)
    at org.testcontainers.ext.ScriptUtils.executeDatabaseScript(ScriptUtils.java:313)
    at org.testcontainers.jdbc.ContainerDatabaseDriver.runInitScriptIfRequired(ContainerDatabaseDriver.java:196)
    at org.testcontainers.jdbc.ContainerDatabaseDriver.connect(ContainerDatabaseDriver.java:132)
    at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:136)
    at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:369)
    at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:198)
    at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:467)
    at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:541)
    ... 61 more
Caused by: org.testcontainers.ext.ScriptUtils$ScriptStatementFailedException: Script execution failed (component/db/init_mysql.sql:1): create schema new_schema CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
    at org.testcontainers.jdbc.JdbcDatabaseDelegate.execute(JdbcDatabaseDelegate.java:49)
    at org.testcontainers.delegate.AbstractDatabaseDelegate.execute(AbstractDatabaseDelegate.java:34)
    at org.testcontainers.ext.ScriptUtils.executeDatabaseScript(ScriptUtils.java:362)
    ... 69 more
Caused by: java.sql.SQLSyntaxErrorException: Access denied for user 'test'@'%' to database 'new_schema'
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
    at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
    at com.mysql.cj.jdbc.StatementImpl.executeInternal(StatementImpl.java:782)
    at com.mysql.cj.jdbc.StatementImpl.execute(StatementImpl.java:666)
    at org.testcontainers.jdbc.JdbcDatabaseDelegate.execute(JdbcDatabaseDelegate.java:42)
    ... 71 more

组件/db/init_mysql.sql

create schema new_schema CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

在 JDBC 集成之外创建 mysql 映像时遇到类似问题:

private static final MySQLContainer mysqlContainer = new MySQLContainer<>(DockerImageName.parse("mysql:5.7"))
            .withInitScript("component/db/init_mysql.sql")
            .withUsername("user")
            .withPassword("password")
            .withExposedPorts(3306)
            .withReuse(true);

关于如何在不使用预先创建的架构创建自定义 docker 映像的情况下实现这一点的任何想法?

任何帮助将不胜感激我觉得我一定在这里遗漏了一些东西。

【问题讨论】:

也在这里提出github.com/testcontainers/testcontainers-java/issues/… 【参考方案1】:

尝试创建 MySQL 容器并为root 使用与test 用户相同的密码,在本例中为whatever

@Container
private static MySQLContainer database = new MySQLContainer(MYSQL_DOCKER_TEST_VERSION)
            .withUsername("test")
            .withPassword("whatever")
...

通过@DynamicPropertySource 动态添加属性。

    @DynamicPropertySource
    static void databaseProperties(DynamicPropertyRegistry registry) 
        registry.add("spring.datasource.url", database::getJdbcUrl);
        registry.add("spring.datasource.username", database::getUsername);
        registry.add("spring.datasource.password", database::getPassword);
        registry.add("flyway.user", () -> "root");
        registry.add("flyway.password", database::getPassword);
    

我没有使用 flyway,但我相信它应该可以工作。

【讨论】:

【参考方案2】:

正如在 testcontainers 存储库上创建的测试中所见,解决方法是指定 root 用户的密码并在测试中使用 root 用户:

MySQLContainer<?> db = new MySQLContainer<>(image)
            .withUsername("test")
            .withPassword("test")
            .withEnv("MYSQL_ROOT_PASSWORD", "test")
            ...

参考:https://github.com/testcontainers/testcontainers-java/commit/2fa00ddbd1f42a20656d5e39d58cdedfbd483dcf#diff-f49cf0d09246a5351504ca32a08deb74e80ac7d61ad012f02d8f09c36508737bR65

【讨论】:

【参考方案3】:

通过使用预先创建的模式创建自定义 MySQL 映像来解决此问题。很想知道是否有更好的方法。

【讨论】:

这不是一个坏方法,因为预创建的图像使容器启动时间更短。 您是如何实施此解决方案的?我有同样的问题,不胜感激。【参考方案4】:

我遇到了同样的问题,我使用以下方法解决了它:

    @Container
     public static JdbcDatabaseContainer mariaDB = (JdbcDatabaseContainer) new MariaDBContainer("mariadb:10.5.11-focal")
    .withDatabaseName("dbName")
    .withInitScript("db.migration/init.sql")
    .withUsername("your user")
    .withPassword("your password")
    .withUrlParam("param", "1")
    .withUrlParam("param", "2");

基本上,我是通过 POJO 创建数据库的。有点hackish但有效。但也许使用自定义密码创建 root 用户是一个更好的解决方案。

【讨论】:

以上是关于MySQL TestContainers init-script 模式创建失败的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Testcontainers 将可执行文件复制到 Docker 容器

使用测试容器播种 mysql 数据库

java单元/集成测试中使用Testcontainers

java单元/集成测试中使用Testcontainers

Spring testcontainers Driver org.testcontainers.jdbc.ContainerDatabaseDriver 声称不接受 jdbcUrl

testcontainers 方便的db测试框架