diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/MySQLIdentityColumnMaxValueIncrementer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/MySQLIdentityColumnMaxValueIncrementer.java new file mode 100644 index 000000000000..02d52d732f34 --- /dev/null +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/MySQLIdentityColumnMaxValueIncrementer.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.jdbc.support.incrementer; + +import javax.sql.DataSource; + +/** + * {@link DataFieldMaxValueIncrementer} that increments the maximum counter value of an + * auto-increment column of a given MySQL table. + * + *

The sequence is kept in a table. The storage engine used by the sequence table must be + * InnoDB in MySQL 8.0 or later since the current maximum auto-increment counter is required to be + * persisted across restarts of the database server. + * + *

Example: + * + *

+ * create table tab_sequence (`id` bigint unsigned primary key auto_increment);
+ * + *

If {@code cacheSize} is set, the intermediate values are served without querying the + * database. If the server or your application is stopped or crashes or a transaction + * is rolled back, the unused values will never be served. The maximum hole size in + * numbering is consequently the value of {@code cacheSize}. + * + * @author Henning Pƶttker + * @since 6.1.2 + */ +public class MySQLIdentityColumnMaxValueIncrementer extends AbstractIdentityColumnMaxValueIncrementer { + + /** + * Default constructor for bean property style usage. + * @see #setDataSource + * @see #setIncrementerName + * @see #setColumnName + */ + public MySQLIdentityColumnMaxValueIncrementer() { + } + + /** + * Convenience constructor. + * @param dataSource the DataSource to use + * @param incrementerName the name of the sequence table to use + * @param columnName the name of the column in the sequence table to use + */ + public MySQLIdentityColumnMaxValueIncrementer(DataSource dataSource, String incrementerName, String columnName) { + super(dataSource, incrementerName, columnName); + } + + @Override + protected String getIncrementStatement() { + return "insert into " + getIncrementerName() + " () values ()"; + } + + @Override + protected String getIdentityStatement() { + return "select last_insert_id()"; + } + +} diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/support/incrementer/DataFieldMaxValueIncrementerTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/support/incrementer/DataFieldMaxValueIncrementerTests.java index 0fb7a6cbfbed..95610de294c7 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/support/incrementer/DataFieldMaxValueIncrementerTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/support/incrementer/DataFieldMaxValueIncrementerTests.java @@ -133,6 +133,33 @@ void hsqlMaxValueIncrementerWithDeleteSpecificValues() throws SQLException { verify(connection, times(2)).close(); } + @Test + void mySQLIdentityColumnMaxValueIncrementer() throws SQLException { + given(dataSource.getConnection()).willReturn(connection); + given(connection.createStatement()).willReturn(statement); + given(statement.executeQuery("select last_insert_id()")).willReturn(resultSet); + given(resultSet.next()).willReturn(true); + given(resultSet.getLong(1)).willReturn(1L, 2L, 3L, 4L); + + MySQLIdentityColumnMaxValueIncrementer incrementer = new MySQLIdentityColumnMaxValueIncrementer(); + incrementer.setDataSource(dataSource); + incrementer.setIncrementerName("myseq"); + incrementer.setColumnName("seq"); + incrementer.setCacheSize(2); + incrementer.setPaddingLength(1); + incrementer.afterPropertiesSet(); + + assertThat(incrementer.nextIntValue()).isEqualTo(1); + assertThat(incrementer.nextLongValue()).isEqualTo(2); + assertThat(incrementer.nextStringValue()).isEqualTo("3"); + assertThat(incrementer.nextLongValue()).isEqualTo(4); + + verify(statement, times(4)).executeUpdate("insert into myseq () values ()"); + verify(resultSet, times(4)).close(); + verify(statement, times(2)).close(); + verify(connection, times(2)).close(); + } + @Test void mySQLMaxValueIncrementer() throws SQLException { given(dataSource.getConnection()).willReturn(connection);