From 5e45b9be1b742c7493e2bafbb0f1d1d0828194e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A8=B8=EB=9E=AD?= <113977176+cookie-meringue@users.noreply.github.com> Date: Sun, 4 Oct 2026 01:36:50 +0900 Subject: [PATCH] Fix connection leak in MySQLMaxValueIncrementer Move connection cleanup into a finally block so the connection is closed even if commit or auto-commit restoration fails. Closes gh-37321 Signed-off-by: cookie-meringue --- .../incrementer/MySQLMaxValueIncrementer.java | 4 +- .../DataFieldMaxValueIncrementerTests.java | 50 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/MySQLMaxValueIncrementer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/MySQLMaxValueIncrementer.java index 7c364586dac..0bd252a8143 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/MySQLMaxValueIncrementer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/MySQLMaxValueIncrementer.java @@ -182,7 +182,9 @@ public class MySQLMaxValueIncrementer extends AbstractColumnMaxValueIncrementer throw new DataAccessResourceFailureException( "Unable to commit new sequence value changes for " + getIncrementerName()); } - JdbcUtils.closeConnection(con); + finally { + JdbcUtils.closeConnection(con); + } } else { DataSourceUtils.releaseConnection(con, getDataSource()); 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 d9e73d76d83..b25c38084b2 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 @@ -25,8 +25,12 @@ import javax.sql.DataSource; import org.junit.jupiter.api.Test; +import org.springframework.dao.DataAccessResourceFailureException; + import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.willThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -187,6 +191,52 @@ class DataFieldMaxValueIncrementerTests { verify(connection, times(2)).close(); } + @Test + void mySQLMaxValueIncrementerClosesConnectionOnCommitFailure() 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); + willThrow(new SQLException("commit failed")).given(connection).commit(); + + MySQLMaxValueIncrementer incrementer = new MySQLMaxValueIncrementer(); + incrementer.setDataSource(dataSource); + incrementer.setIncrementerName("myseq"); + incrementer.setColumnName("seq"); + incrementer.afterPropertiesSet(); + + assertThatExceptionOfType(DataAccessResourceFailureException.class) + .isThrownBy(incrementer::nextLongValue); + + verify(connection).commit(); + verify(connection).close(); + } + + @Test + void mySQLMaxValueIncrementerClosesConnectionOnAutoCommitRestoreFailure() throws SQLException { + given(dataSource.getConnection()).willReturn(connection); + given(connection.getAutoCommit()).willReturn(true); + 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); + willThrow(new SQLException("autoCommit restore failed")).given(connection).setAutoCommit(true); + + MySQLMaxValueIncrementer incrementer = new MySQLMaxValueIncrementer(); + incrementer.setDataSource(dataSource); + incrementer.setIncrementerName("myseq"); + incrementer.setColumnName("seq"); + incrementer.afterPropertiesSet(); + + assertThatExceptionOfType(DataAccessResourceFailureException.class) + .isThrownBy(incrementer::nextLongValue); + + verify(connection).commit(); + verify(connection).setAutoCommit(true); + verify(connection).close(); + } + @Test void mariaDBSequenceMaxValueIncrementer() throws SQLException { given(dataSource.getConnection()).willReturn(connection);