Skip to content

Commit 524e956

Browse files
committed
Add full support for MariaDB
This commit adds full support for MariaDB as a job repository and removes the code that treats it as MySQL. Resolves #3891 Resolves #4217
1 parent 724cc97 commit 524e956

File tree

15 files changed

+503
-3
lines changed

15 files changed

+503
-3
lines changed

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
<woodstox-core.version>6.3.1</woodstox-core.version>
107107
<aspectj.version>1.9.9.1</aspectj.version>
108108
<mysql-connector-j.version>8.0.31</mysql-connector-j.version>
109+
<mariadb-java-client.version>3.0.8</mariadb-java-client.version>
109110
<postgresql.version>42.5.0</postgresql.version>
110111
<db2.version>11.5.7.0</db2.version>
111112
<oracle.version>19.16.0.0</oracle.version>

spring-batch-core/pom.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,18 @@
118118
<version>${testcontainers.version}</version>
119119
<scope>test</scope>
120120
</dependency>
121+
<dependency>
122+
<groupId>org.mariadb.jdbc</groupId>
123+
<artifactId>mariadb-java-client</artifactId>
124+
<version>${mariadb-java-client.version}</version>
125+
<scope>test</scope>
126+
</dependency>
127+
<dependency>
128+
<groupId>org.testcontainers</groupId>
129+
<artifactId>mariadb</artifactId>
130+
<version>${testcontainers.version}</version>
131+
<scope>test</scope>
132+
</dependency>
121133
<dependency>
122134
<groupId>org.postgresql</groupId>
123135
<artifactId>postgresql</artifactId>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Placeholders batch.*
2+
# for MariaDB:
3+
batch.jdbc.driver=org.mariadb.jdbc.Driver
4+
batch.jdbc.url=jdbc:mariadb://localhost/test
5+
batch.jdbc.user=test
6+
batch.jdbc.password=test
7+
batch.database.incrementer.class=org.springframework.batch.item.database.support.MariaDBSequenceMaxValueIncrementer
8+
batch.schema.script=classpath:/org/springframework/batch/core/schema-mariadb.sql
9+
batch.drop.script=classpath:/org/springframework/batch/core/schema-drop-mariadb.sql
10+
batch.jdbc.testWhileIdle=true
11+
batch.jdbc.validationQuery=
12+
13+
14+
# Non-platform dependent settings that you might like to change
15+
batch.data.source.init=true
16+
batch.table.prefix=BATCH_
17+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
DROP TABLE IF EXISTS BATCH_STEP_EXECUTION_CONTEXT;
2+
DROP TABLE IF EXISTS BATCH_JOB_EXECUTION_CONTEXT;
3+
DROP TABLE IF EXISTS BATCH_STEP_EXECUTION;
4+
DROP TABLE IF EXISTS BATCH_JOB_EXECUTION_PARAMS;
5+
DROP TABLE IF EXISTS BATCH_JOB_EXECUTION;
6+
DROP TABLE IF EXISTS BATCH_JOB_INSTANCE;
7+
8+
DROP SEQUENCE IF EXISTS BATCH_STEP_EXECUTION_SEQ;
9+
DROP SEQUENCE IF EXISTS BATCH_JOB_EXECUTION_SEQ;
10+
DROP SEQUENCE IF EXISTS BATCH_JOB_SEQ;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
CREATE TABLE BATCH_JOB_INSTANCE (
2+
JOB_INSTANCE_ID BIGINT NOT NULL PRIMARY KEY ,
3+
VERSION BIGINT ,
4+
JOB_NAME VARCHAR(100) NOT NULL,
5+
JOB_KEY VARCHAR(32) NOT NULL,
6+
constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY)
7+
) ENGINE=InnoDB;
8+
9+
CREATE TABLE BATCH_JOB_EXECUTION (
10+
JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,
11+
VERSION BIGINT ,
12+
JOB_INSTANCE_ID BIGINT NOT NULL,
13+
CREATE_TIME DATETIME(6) NOT NULL,
14+
START_TIME DATETIME(6) DEFAULT NULL ,
15+
END_TIME DATETIME(6) DEFAULT NULL ,
16+
STATUS VARCHAR(10) ,
17+
EXIT_CODE VARCHAR(2500) ,
18+
EXIT_MESSAGE VARCHAR(2500) ,
19+
LAST_UPDATED DATETIME(6),
20+
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
21+
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
22+
) ENGINE=InnoDB;
23+
24+
CREATE TABLE BATCH_JOB_EXECUTION_PARAMS (
25+
JOB_EXECUTION_ID BIGINT NOT NULL ,
26+
PARAMETER_NAME VARCHAR(100) NOT NULL ,
27+
PARAMETER_TYPE VARCHAR(100) NOT NULL ,
28+
PARAMETER_VALUE VARCHAR(2500) ,
29+
IDENTIFYING CHAR(1) NOT NULL ,
30+
constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
31+
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
32+
) ENGINE=InnoDB;
33+
34+
CREATE TABLE BATCH_STEP_EXECUTION (
35+
STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,
36+
VERSION BIGINT NOT NULL,
37+
STEP_NAME VARCHAR(100) NOT NULL,
38+
JOB_EXECUTION_ID BIGINT NOT NULL,
39+
CREATE_TIME DATETIME(6) NOT NULL,
40+
START_TIME DATETIME(6) DEFAULT NULL ,
41+
END_TIME DATETIME(6) DEFAULT NULL ,
42+
STATUS VARCHAR(10) ,
43+
COMMIT_COUNT BIGINT ,
44+
READ_COUNT BIGINT ,
45+
FILTER_COUNT BIGINT ,
46+
WRITE_COUNT BIGINT ,
47+
READ_SKIP_COUNT BIGINT ,
48+
WRITE_SKIP_COUNT BIGINT ,
49+
PROCESS_SKIP_COUNT BIGINT ,
50+
ROLLBACK_COUNT BIGINT ,
51+
EXIT_CODE VARCHAR(2500) ,
52+
EXIT_MESSAGE VARCHAR(2500) ,
53+
LAST_UPDATED DATETIME(6),
54+
constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID)
55+
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
56+
) ENGINE=InnoDB;
57+
58+
CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT (
59+
STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
60+
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
61+
SERIALIZED_CONTEXT TEXT ,
62+
constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID)
63+
references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID)
64+
) ENGINE=InnoDB;
65+
66+
CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT (
67+
JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
68+
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
69+
SERIALIZED_CONTEXT TEXT ,
70+
constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)
71+
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
72+
) ENGINE=InnoDB;
73+
74+
CREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ START WITH 1 MINVALUE 1 MAXVALUE 9223372036854775806 INCREMENT BY 1 NOCACHE NOCYCLE ENGINE=InnoDB;
75+
CREATE SEQUENCE BATCH_JOB_EXECUTION_SEQ START WITH 1 MINVALUE 1 MAXVALUE 9223372036854775806 INCREMENT BY 1 NOCACHE NOCYCLE ENGINE=InnoDB;
76+
CREATE SEQUENCE BATCH_JOB_SEQ START WITH 1 MINVALUE 1 MAXVALUE 9223372036854775806 INCREMENT BY 1 NOCACHE NOCYCLE ENGINE=InnoDB;
77+
78+
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Copyright 2022 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+
package org.springframework.batch.core.test.repository;
17+
18+
import javax.sql.DataSource;
19+
20+
import org.junit.jupiter.api.BeforeEach;
21+
import org.junit.jupiter.api.Test;
22+
import org.mariadb.jdbc.MariaDbDataSource;
23+
import org.testcontainers.containers.MariaDBContainer;
24+
import org.testcontainers.junit.jupiter.Container;
25+
import org.testcontainers.junit.jupiter.Testcontainers;
26+
import org.testcontainers.utility.DockerImageName;
27+
28+
import org.springframework.batch.core.ExitStatus;
29+
import org.springframework.batch.core.Job;
30+
import org.springframework.batch.core.JobExecution;
31+
import org.springframework.batch.core.JobParameters;
32+
import org.springframework.batch.core.JobParametersBuilder;
33+
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
34+
import org.springframework.batch.core.job.builder.JobBuilder;
35+
import org.springframework.batch.core.launch.JobLauncher;
36+
import org.springframework.batch.core.repository.JobRepository;
37+
import org.springframework.batch.core.step.builder.StepBuilder;
38+
import org.springframework.batch.repeat.RepeatStatus;
39+
import org.springframework.beans.factory.annotation.Autowired;
40+
import org.springframework.context.annotation.Bean;
41+
import org.springframework.context.annotation.Configuration;
42+
import org.springframework.core.io.ClassPathResource;
43+
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
44+
import org.springframework.jdbc.support.JdbcTransactionManager;
45+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
46+
import org.springframework.transaction.PlatformTransactionManager;
47+
48+
import static org.junit.jupiter.api.Assertions.assertEquals;
49+
import static org.junit.jupiter.api.Assertions.assertNotNull;
50+
51+
/**
52+
* @author Mahmoud Ben Hassine
53+
*/
54+
@Testcontainers
55+
@SpringJUnitConfig
56+
class MariaDBJobRepositoryIntegrationTests {
57+
58+
// TODO find the best way to externalize and manage image versions
59+
private static final DockerImageName MARIADB_IMAGE = DockerImageName.parse("mariadb:10.9.3");
60+
61+
@Container
62+
public static MariaDBContainer<?> mariaDBContainer = new MariaDBContainer<>(MARIADB_IMAGE);
63+
64+
@Autowired
65+
private DataSource dataSource;
66+
67+
@Autowired
68+
private JobLauncher jobLauncher;
69+
70+
@Autowired
71+
private Job job;
72+
73+
@BeforeEach
74+
void setUp() {
75+
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
76+
databasePopulator.addScript(new ClassPathResource("/org/springframework/batch/core/schema-mariadb.sql"));
77+
databasePopulator.execute(this.dataSource);
78+
}
79+
80+
@Test
81+
void testJobExecution() throws Exception {
82+
// given
83+
JobParameters jobParameters = new JobParametersBuilder().toJobParameters();
84+
85+
// when
86+
JobExecution jobExecution = this.jobLauncher.run(this.job, jobParameters);
87+
88+
// then
89+
assertNotNull(jobExecution);
90+
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
91+
}
92+
93+
@Configuration
94+
@EnableBatchProcessing
95+
static class TestConfiguration {
96+
97+
@Bean
98+
public DataSource dataSource() throws Exception {
99+
MariaDbDataSource datasource = new MariaDbDataSource();
100+
datasource.setUrl(mariaDBContainer.getJdbcUrl());
101+
datasource.setUser(mariaDBContainer.getUsername());
102+
datasource.setPassword(mariaDBContainer.getPassword());
103+
return datasource;
104+
}
105+
106+
@Bean
107+
public JdbcTransactionManager transactionManager(DataSource dataSource) {
108+
return new JdbcTransactionManager(dataSource);
109+
}
110+
111+
@Bean
112+
public Job job(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
113+
return new JobBuilder("job", jobRepository)
114+
.start(new StepBuilder("step", jobRepository)
115+
.tasklet((contribution, chunkContext) -> RepeatStatus.FINISHED, transactionManager).build())
116+
.build();
117+
}
118+
119+
}
120+
121+
}

spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/JdbcPagingItemReaderBuilder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.batch.item.database.support.H2PagingQueryProvider;
2828
import org.springframework.batch.item.database.support.HanaPagingQueryProvider;
2929
import org.springframework.batch.item.database.support.HsqlPagingQueryProvider;
30+
import org.springframework.batch.item.database.support.MariaDBPagingQueryProvider;
3031
import org.springframework.batch.item.database.support.MySqlPagingQueryProvider;
3132
import org.springframework.batch.item.database.support.OraclePagingQueryProvider;
3233
import org.springframework.batch.item.database.support.PostgresPagingQueryProvider;
@@ -49,6 +50,7 @@
4950
* @author Michael Minella
5051
* @author Glenn Renfro
5152
* @author Drummond Dawson
53+
* @author Mahmoud Ben Hassine
5254
* @since 4.0
5355
* @see JdbcPagingItemReader
5456
*/
@@ -360,6 +362,9 @@ private PagingQueryProvider determineQueryProvider(DataSource dataSource) {
360362
case MYSQL:
361363
provider = new MySqlPagingQueryProvider();
362364
break;
365+
case MARIADB:
366+
provider = new MariaDBPagingQueryProvider();
367+
break;
363368
case ORACLE:
364369
provider = new OraclePagingQueryProvider();
365370
break;

spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/DefaultDataFieldMaxValueIncrementerFactory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import static org.springframework.batch.support.DatabaseType.H2;
4141
import static org.springframework.batch.support.DatabaseType.HANA;
4242
import static org.springframework.batch.support.DatabaseType.HSQL;
43+
import static org.springframework.batch.support.DatabaseType.MARIADB;
4344
import static org.springframework.batch.support.DatabaseType.MYSQL;
4445
import static org.springframework.batch.support.DatabaseType.ORACLE;
4546
import static org.springframework.batch.support.DatabaseType.POSTGRES;
@@ -109,6 +110,9 @@ else if (databaseType == MYSQL) {
109110
mySQLMaxValueIncrementer.setUseNewConnection(true);
110111
return mySQLMaxValueIncrementer;
111112
}
113+
else if (databaseType == MARIADB) {
114+
return new MariaDBSequenceMaxValueIncrementer(dataSource, incrementerName);
115+
}
112116
else if (databaseType == ORACLE) {
113117
return new OracleSequenceMaxValueIncrementer(dataSource, incrementerName);
114118
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2022 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.batch.item.database.support;
18+
19+
import org.springframework.batch.item.database.PagingQueryProvider;
20+
import org.springframework.util.StringUtils;
21+
22+
/**
23+
* MariaDB implementation of a {@link PagingQueryProvider} using database specific
24+
* features.
25+
*
26+
* @author Mahmoud Ben Hassine
27+
* @since 5.0
28+
*/
29+
public class MariaDBPagingQueryProvider extends AbstractSqlPagingQueryProvider {
30+
31+
@Override
32+
public String generateFirstPageQuery(int pageSize) {
33+
return SqlPagingQueryUtils.generateLimitSqlQuery(this, false, buildLimitClause(pageSize));
34+
}
35+
36+
@Override
37+
public String generateRemainingPagesQuery(int pageSize) {
38+
if (StringUtils.hasText(getGroupClause())) {
39+
return SqlPagingQueryUtils.generateLimitGroupedSqlQuery(this, buildLimitClause(pageSize));
40+
}
41+
else {
42+
return SqlPagingQueryUtils.generateLimitSqlQuery(this, true, buildLimitClause(pageSize));
43+
}
44+
}
45+
46+
private String buildLimitClause(int pageSize) {
47+
return new StringBuilder().append("LIMIT ").append(pageSize).toString();
48+
}
49+
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2022 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+
* http://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.batch.item.database.support;
18+
19+
import javax.sql.DataSource;
20+
21+
import org.springframework.jdbc.support.incrementer.AbstractSequenceMaxValueIncrementer;
22+
import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
23+
24+
/**
25+
* {@link DataFieldMaxValueIncrementer} for MariaDB.
26+
*
27+
* @author Mahmoud Ben Hassine
28+
* @since 5.0
29+
*/
30+
// TODO replace this with the one from Spring Framework when available
31+
public class MariaDBSequenceMaxValueIncrementer extends AbstractSequenceMaxValueIncrementer {
32+
33+
public MariaDBSequenceMaxValueIncrementer() {
34+
}
35+
36+
public MariaDBSequenceMaxValueIncrementer(DataSource dataSource, String incrementerName) {
37+
super(dataSource, incrementerName);
38+
}
39+
40+
@Override
41+
protected String getSequenceQuery() {
42+
return "select next value for " + this.getIncrementerName();
43+
}
44+
45+
}

0 commit comments

Comments
 (0)