Skip to content

Commit 92fe4c5

Browse files
committed
Resolve MariaDB and MySQL dialects through DB query
Spring Data JDBC has deprecated its INSTANCE constants in its MariaDB and MySQL dialects as the required configuration for the dialect varies depending on the configuration of the DB. This commit adapts to this deprecation by changing Boot's DataJdbcDatabaseDialect to resolve the underlying dialect through a DB query for its MARIA and MYSQL values. Closes gh-46062
1 parent 911578e commit 92fe4c5

File tree

6 files changed

+136
-13
lines changed

6 files changed

+136
-13
lines changed

module/spring-boot-data-jdbc/build.gradle

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ plugins {
1919
id "org.springframework.boot.auto-configuration"
2020
id "org.springframework.boot.configuration-properties"
2121
id "org.springframework.boot.deployed"
22+
id "org.springframework.boot.docker-test"
2223
id "org.springframework.boot.optional-dependencies"
2324
}
2425

@@ -31,6 +32,17 @@ dependencies {
3132

3233
optional(project(":core:spring-boot-autoconfigure"))
3334

35+
dockerTestImplementation(project(":core:spring-boot-test"))
36+
dockerTestImplementation(project(":test-support:spring-boot-docker-test-support"))
37+
dockerTestImplementation(testFixtures(project(":core:spring-boot-autoconfigure")))
38+
dockerTestImplementation("ch.qos.logback:logback-classic")
39+
dockerTestImplementation("org.testcontainers:mariadb")
40+
dockerTestImplementation("org.testcontainers:mysql")
41+
42+
dockerTestRuntimeOnly("com.mysql:mysql-connector-j")
43+
dockerTestRuntimeOnly("com.zaxxer:HikariCP")
44+
dockerTestRuntimeOnly("org.mariadb.jdbc:mariadb-java-client")
45+
3446
testImplementation(project(":core:spring-boot-test"))
3547
testImplementation(project(":test-support:spring-boot-test-support"))
3648
testImplementation(testFixtures(project(":core:spring-boot-autoconfigure")))
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright 2012-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.data.jdbc.autoconfigure;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.testcontainers.containers.JdbcDatabaseContainer;
21+
import org.testcontainers.containers.MariaDBContainer;
22+
import org.testcontainers.containers.MySQLContainer;
23+
24+
import org.springframework.boot.autoconfigure.AutoConfigurations;
25+
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
26+
import org.springframework.boot.data.jdbc.domain.city.City;
27+
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
28+
import org.springframework.boot.jdbc.autoconfigure.DataSourceTransactionManagerAutoConfiguration;
29+
import org.springframework.boot.jdbc.autoconfigure.JdbcTemplateAutoConfiguration;
30+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
31+
import org.springframework.boot.testsupport.container.TestImage;
32+
import org.springframework.data.jdbc.core.dialect.JdbcMySqlDialect;
33+
import org.springframework.data.relational.core.dialect.Dialect;
34+
import org.springframework.data.relational.core.dialect.MariaDbDialect;
35+
import org.springframework.util.function.ThrowingConsumer;
36+
37+
import static org.assertj.core.api.Assertions.assertThat;
38+
39+
/**
40+
* Tests for {@link DataJdbcRepositoriesAutoConfiguration} when the configured dialect
41+
* requires resolution using a database connection.
42+
*
43+
* @author Andy Wilkinson
44+
*/
45+
class DataJdbcRepositoriesAutoConfigurationDialectResolutionTests {
46+
47+
@Test
48+
void resolvesMariaDbDialect() {
49+
withContainer(MariaDBContainer.class, (runner) -> {
50+
runner.withPropertyValues("spring.data.jdbc.dialect=maria").run((context) -> {
51+
Dialect dialect = context.getBean(Dialect.class);
52+
assertThat(dialect).isInstanceOf(MariaDbDialect.class);
53+
});
54+
});
55+
}
56+
57+
@Test
58+
void resolvesMySqlDialect() {
59+
withContainer(MySQLContainer.class, (runner) -> {
60+
runner.withPropertyValues("spring.data.jdbc.dialect=mysql").run((context) -> {
61+
Dialect dialect = context.getBean(Dialect.class);
62+
assertThat(dialect).isInstanceOf(JdbcMySqlDialect.class);
63+
});
64+
});
65+
}
66+
67+
private <C extends JdbcDatabaseContainer<?>> void withContainer(Class<C> containerType,
68+
ThrowingConsumer<ApplicationContextRunner> callback) {
69+
C container = TestImage.container(containerType);
70+
try {
71+
container.start();
72+
ApplicationContextRunner contextRunner = new ApplicationContextRunner()
73+
.withConfiguration(AutoConfigurations.of(DataSourceAutoConfiguration.class,
74+
DataJdbcRepositoriesAutoConfiguration.class, JdbcTemplateAutoConfiguration.class,
75+
DataSourceTransactionManagerAutoConfiguration.class))
76+
.withUserConfiguration(TestConfiguration.class)
77+
.withPropertyValues("spring.datasource.url=" + container.getJdbcUrl(),
78+
"spring.datasource.username=" + container.getUsername(),
79+
"spring.datasource.password=" + container.getPassword());
80+
callback.accept(contextRunner);
81+
}
82+
finally {
83+
container.close();
84+
}
85+
}
86+
87+
@TestAutoConfigurationPackage(City.class)
88+
static class TestConfiguration {
89+
90+
}
91+
92+
}

module/spring-boot-data-jdbc/src/main/java/org/springframework/boot/data/jdbc/autoconfigure/DataJdbcDatabaseDialect.java

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,20 @@
1616

1717
package org.springframework.boot.data.jdbc.autoconfigure;
1818

19+
import java.util.function.Function;
20+
21+
import org.springframework.data.jdbc.core.dialect.DialectResolver;
1922
import org.springframework.data.jdbc.core.dialect.JdbcDb2Dialect;
2023
import org.springframework.data.jdbc.core.dialect.JdbcH2Dialect;
2124
import org.springframework.data.jdbc.core.dialect.JdbcHsqlDbDialect;
25+
import org.springframework.data.jdbc.core.dialect.JdbcMariaDbDialect;
2226
import org.springframework.data.jdbc.core.dialect.JdbcMySqlDialect;
2327
import org.springframework.data.jdbc.core.dialect.JdbcOracleDialect;
2428
import org.springframework.data.jdbc.core.dialect.JdbcPostgresDialect;
2529
import org.springframework.data.jdbc.core.dialect.JdbcSqlServerDialect;
2630
import org.springframework.data.relational.core.dialect.Dialect;
31+
import org.springframework.jdbc.core.JdbcOperations;
32+
import org.springframework.util.Assert;
2733

2834
/**
2935
* List of database dialects that can be configured in Boot for use with Spring Data JDBC.
@@ -49,16 +55,16 @@ public enum DataJdbcDatabaseDialect {
4955
HSQL(JdbcHsqlDbDialect.INSTANCE),
5056

5157
/**
52-
* Provides an instance of {@link JdbcMySqlDialect}.
58+
* Resolves an instance of {@link JdbcMariaDbDialect} by querying the database
59+
* configuration.
5360
*/
54-
@SuppressWarnings("removal")
55-
MARIA(JdbcMySqlDialect.INSTANCE),
61+
MARIA(JdbcMariaDbDialect.class),
5662

5763
/**
58-
* Provides an instance of {@link JdbcMySqlDialect}.
64+
* Resolves an instance of {@link JdbcMySqlDialect} by querying the database
65+
* configuration.
5966
*/
60-
@SuppressWarnings("removal")
61-
MYSQL(JdbcMySqlDialect.INSTANCE),
67+
MYSQL(JdbcMySqlDialect.class),
6268

6369
/**
6470
* Provides an instance of {@link JdbcOracleDialect}.
@@ -75,14 +81,22 @@ public enum DataJdbcDatabaseDialect {
7581
*/
7682
SQL_SERVER(JdbcSqlServerDialect.INSTANCE);
7783

78-
private final Dialect dialect;
84+
private final Function<JdbcOperations, Dialect> dialectResolver;
85+
86+
DataJdbcDatabaseDialect(Class<? extends Dialect> dialectType) {
87+
this.dialectResolver = (jdbc) -> {
88+
Dialect dialect = DialectResolver.getDialect(jdbc);
89+
Assert.isInstanceOf(dialectType, dialect);
90+
return dialect;
91+
};
92+
}
7993

8094
DataJdbcDatabaseDialect(Dialect dialect) {
81-
this.dialect = dialect;
95+
this.dialectResolver = (jdbc) -> dialect;
8296
}
8397

84-
final Dialect getDialect() {
85-
return this.dialect;
98+
Dialect getDialect(JdbcOperations jdbc) {
99+
return this.dialectResolver.apply(jdbc);
86100
}
87101

88102
}

module/spring-boot-data-jdbc/src/main/java/org/springframework/boot/data/jdbc/autoconfigure/DataJdbcRepositoriesAutoConfiguration.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ public DataAccessStrategy dataAccessStrategyBean(NamedParameterJdbcOperations op
147147
@ConditionalOnMissingBean
148148
public Dialect jdbcDialect(NamedParameterJdbcOperations operations) {
149149
DataJdbcDatabaseDialect dialect = this.properties.getDialect();
150-
return (dialect != null) ? dialect.getDialect() : super.jdbcDialect(operations);
150+
return (dialect != null) ? dialect.getDialect(operations.getJdbcOperations())
151+
: super.jdbcDialect(operations);
151152
}
152153

153154
}

test-support/spring-boot-docker-test-support/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ dependencies {
3838
optional("org.testcontainers:junit-jupiter")
3939
optional("org.testcontainers:kafka")
4040
optional("org.testcontainers:ldap")
41+
optional("org.testcontainers:mariadb")
4142
optional("org.testcontainers:mongodb")
43+
optional("org.testcontainers:mysql")
4244
optional("org.testcontainers:neo4j")
4345
optional("org.testcontainers:oracle-xe")
4446
optional("org.testcontainers:oracle-free")

test-support/spring-boot-docker-test-support/src/main/java/org/springframework/boot/testsupport/container/TestImage.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
import org.testcontainers.cassandra.CassandraContainer;
3131
import org.testcontainers.containers.Container;
3232
import org.testcontainers.containers.GenericContainer;
33+
import org.testcontainers.containers.MariaDBContainer;
3334
import org.testcontainers.containers.MongoDBContainer;
35+
import org.testcontainers.containers.MySQLContainer;
3436
import org.testcontainers.containers.Neo4jContainer;
3537
import org.testcontainers.containers.PostgreSQLContainer;
3638
import org.testcontainers.containers.PulsarContainer;
@@ -149,7 +151,7 @@ public enum TestImage {
149151
/**
150152
* A container image suitable for testing MariaDB.
151153
*/
152-
MARIADB("mariadb", "10.10"),
154+
MARIADB("mariadb", "10.10", () -> MariaDBContainer.class),
153155

154156
/**
155157
* A container image suitable for testing MongoDB.
@@ -168,7 +170,7 @@ public enum TestImage {
168170
/**
169171
* A container image suitable for testing MySQL.
170172
*/
171-
MYSQL("mysql", "8.0"),
173+
MYSQL("mysql", "8.0", () -> MySQLContainer.class),
172174

173175
/**
174176
* A container image suitable for testing Neo4j.

0 commit comments

Comments
 (0)