diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractIdentityColumnMaxValueIncrementer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractIdentityColumnMaxValueIncrementer.java new file mode 100644 index 0000000000..d9b38ac70c --- /dev/null +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractIdentityColumnMaxValueIncrementer.java @@ -0,0 +1,163 @@ +/* + * Copyright 2002-2014 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 + * + * http://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 java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import javax.sql.DataSource; + +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.jdbc.datasource.DataSourceUtils; +import org.springframework.jdbc.support.JdbcUtils; + +/** + * Abstract base class for {@link DataFieldMaxValueIncrementer} implementations + * which are based on identity columns in a sequence-like table. + * + * @author Juergen Hoeller + * @author Thomas Risberg + * @since 4.1.2 + */ +public abstract class AbstractIdentityColumnMaxValueIncrementer extends AbstractColumnMaxValueIncrementer { + + private boolean deleteSpecificValues = false; + + /** The current cache of values */ + private long[] valueCache; + + /** The next id to serve from the value cache */ + private int nextValueIndex = -1; + + + /** + * Default constructor for bean property style usage. + * @see #setDataSource + * @see #setIncrementerName + * @see #setColumnName + */ + public AbstractIdentityColumnMaxValueIncrementer() { + } + + public AbstractIdentityColumnMaxValueIncrementer(DataSource dataSource, String incrementerName, String columnName) { + super(dataSource, incrementerName, columnName); + } + + + /** + * Specify whether to delete the entire range below the current maximum key value + * ({@code false} - the default), or the specifically generated values ({@code true}). + * The former mode will use a where range clause whereas the latter will use an in + * clause starting with the lowest value minus 1, just preserving the maximum value. + */ + public void setDeleteSpecificValues(boolean deleteSpecificValues) { + this.deleteSpecificValues = deleteSpecificValues; + } + + /** + * Return whether to delete the entire range below the current maximum key value + * ({@code false} - the default), or the specifically generated values ({@code true}). + */ + public boolean isDeleteSpecificValues() { + return this.deleteSpecificValues; + } + + + @Override + protected synchronized long getNextKey() throws DataAccessException { + if (this.nextValueIndex < 0 || this.nextValueIndex >= getCacheSize()) { + /* + * Need to use straight JDBC code because we need to make sure that the insert and select + * are performed on the same connection (otherwise we can't be sure that @@identity + * returns the correct value) + */ + Connection con = DataSourceUtils.getConnection(getDataSource()); + Statement stmt = null; + try { + stmt = con.createStatement(); + DataSourceUtils.applyTransactionTimeout(stmt, getDataSource()); + this.valueCache = new long[getCacheSize()]; + this.nextValueIndex = 0; + for (int i = 0; i < getCacheSize(); i++) { + stmt.executeUpdate(getIncrementStatement()); + ResultSet rs = stmt.executeQuery(getIdentityStatement()); + try { + if (!rs.next()) { + throw new DataAccessResourceFailureException("Identity statement failed after inserting"); + } + this.valueCache[i] = rs.getLong(1); + } + finally { + JdbcUtils.closeResultSet(rs); + } + } + stmt.executeUpdate(getDeleteStatement(this.valueCache)); + } + catch (SQLException ex) { + throw new DataAccessResourceFailureException("Could not increment identity", ex); + } + finally { + JdbcUtils.closeStatement(stmt); + DataSourceUtils.releaseConnection(con, getDataSource()); + } + } + return this.valueCache[this.nextValueIndex++]; + } + + + /** + * Statement to use to increment the "sequence" value. + * @return the SQL statement to use + */ + protected abstract String getIncrementStatement(); + + /** + * Statement to use to obtain the current identity value. + * @return the SQL statement to use + */ + protected abstract String getIdentityStatement(); + + /** + * Statement to use to clean up "sequence" values. + *
The default implementation either deletes the entire range below + * the current maximum value, or the specifically generated values + * (starting with the lowest minus 1, just preserving the maximum value) + * - according to the {@link #isDeleteSpecificValues()} setting. + * @param values the currently generated key values + * (the number of values corresponds to {@link #getCacheSize()}) + * @return the SQL statement to use + */ + protected String getDeleteStatement(long[] values) { + StringBuilder sb = new StringBuilder(64); + sb.append("delete from ").append(getIncrementerName()).append(" where ").append(getColumnName()); + if (isDeleteSpecificValues()) { + sb.append(" in (").append(values[0] - 1); + for (int i = 0; i < values.length - 1; i++) { + sb.append(", ").append(values[i]); + } + sb.append(")"); + } + else { + long maxValue = values[values.length - 1]; + sb.append(" < ").append(maxValue); + } + return sb.toString(); + } + +} diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/DerbyMaxValueIncrementer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/DerbyMaxValueIncrementer.java index 75b4e10d20..6e0bfe1ad9 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/DerbyMaxValueIncrementer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/DerbyMaxValueIncrementer.java @@ -16,17 +16,8 @@ package org.springframework.jdbc.support.incrementer; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; import javax.sql.DataSource; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.jdbc.datasource.DataSourceUtils; -import org.springframework.jdbc.support.JdbcUtils; - /** * {@link DataFieldMaxValueIncrementer} that increments the maximum value of a given Derby table * with the equivalent of an auto-increment column. Note: If you use this class, your Derby key @@ -62,7 +53,7 @@ import org.springframework.jdbc.support.JdbcUtils; * @author Juergen Hoeller * @since 2.5 */ -public class DerbyMaxValueIncrementer extends AbstractColumnMaxValueIncrementer { +public class DerbyMaxValueIncrementer extends AbstractIdentityColumnMaxValueIncrementer { /** The default for dummy name */ private static final String DEFAULT_DUMMY_NAME = "dummy"; @@ -70,12 +61,6 @@ public class DerbyMaxValueIncrementer extends AbstractColumnMaxValueIncrementer /** The name of the dummy column used for inserts */ private String dummyName = DEFAULT_DUMMY_NAME; - /** The current cache of values */ - private long[] valueCache; - - /** The next id to serve from the value cache */ - private int nextValueIndex = -1; - /** * Default constructor for bean property style usage. @@ -126,45 +111,13 @@ public class DerbyMaxValueIncrementer extends AbstractColumnMaxValueIncrementer @Override - protected synchronized long getNextKey() throws DataAccessException { - if (this.nextValueIndex < 0 || this.nextValueIndex >= getCacheSize()) { - /* - * Need to use straight JDBC code because we need to make sure that the insert and select - * are performed on the same connection (otherwise we can't be sure that last_insert_id() - * returned the correct value) - */ - Connection con = DataSourceUtils.getConnection(getDataSource()); - Statement stmt = null; - try { - stmt = con.createStatement(); - DataSourceUtils.applyTransactionTimeout(stmt, getDataSource()); - this.valueCache = new long[getCacheSize()]; - this.nextValueIndex = 0; - for (int i = 0; i < getCacheSize(); i++) { - stmt.executeUpdate("insert into " + getIncrementerName() + " (" + getDummyName() + ") values(null)"); - ResultSet rs = stmt.executeQuery("select IDENTITY_VAL_LOCAL() from " + getIncrementerName()); - try { - if (!rs.next()) { - throw new DataAccessResourceFailureException("IDENTITY_VAL_LOCAL() failed after executing an update"); - } - this.valueCache[i] = rs.getLong(1); - } - finally { - JdbcUtils.closeResultSet(rs); - } - } - long maxValue = this.valueCache[(this.valueCache.length - 1)]; - stmt.executeUpdate("delete from " + getIncrementerName() + " where " + getColumnName() + " < " + maxValue); - } - catch (SQLException ex) { - throw new DataAccessResourceFailureException("Could not obtain IDENTITY value", ex); - } - finally { - JdbcUtils.closeStatement(stmt); - DataSourceUtils.releaseConnection(con, getDataSource()); - } - } - return this.valueCache[this.nextValueIndex++]; + protected String getIncrementStatement() { + return "insert into " + getIncrementerName() + " (" + getDummyName() + ") values(null)"; + } + + @Override + protected String getIdentityStatement() { + return "select IDENTITY_VAL_LOCAL() from " + getIncrementerName(); } } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/HsqlMaxValueIncrementer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/HsqlMaxValueIncrementer.java index 279ba69be0..11e757ec63 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/HsqlMaxValueIncrementer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/HsqlMaxValueIncrementer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2014 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. @@ -16,18 +16,8 @@ package org.springframework.jdbc.support.incrementer; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - import javax.sql.DataSource; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.jdbc.datasource.DataSourceUtils; -import org.springframework.jdbc.support.JdbcUtils; - /** * {@link DataFieldMaxValueIncrementer} that increments the maximum value of a given HSQL table * with the equivalent of an auto-increment column. Note: If you use this class, your HSQL @@ -55,14 +45,7 @@ import org.springframework.jdbc.support.JdbcUtils; * @author Juergen Hoeller * @see HsqlSequenceMaxValueIncrementer */ -public class HsqlMaxValueIncrementer extends AbstractColumnMaxValueIncrementer { - - /** The current cache of values */ - private long[] valueCache; - - /** The next id to serve from the value cache */ - private int nextValueIndex = -1; - +public class HsqlMaxValueIncrementer extends AbstractIdentityColumnMaxValueIncrementer { /** * Default constructor for bean property style usage. @@ -85,45 +68,13 @@ public class HsqlMaxValueIncrementer extends AbstractColumnMaxValueIncrementer { @Override - protected synchronized long getNextKey() throws DataAccessException { - if (this.nextValueIndex < 0 || this.nextValueIndex >= getCacheSize()) { - /* - * Need to use straight JDBC code because we need to make sure that the insert and select - * are performed on the same Connection. Otherwise we can't be sure that last_insert_id() - * returned the correct value. - */ - Connection con = DataSourceUtils.getConnection(getDataSource()); - Statement stmt = null; - try { - stmt = con.createStatement(); - DataSourceUtils.applyTransactionTimeout(stmt, getDataSource()); - this.valueCache = new long[getCacheSize()]; - this.nextValueIndex = 0; - for (int i = 0; i < getCacheSize(); i++) { - stmt.executeUpdate("insert into " + getIncrementerName() + " values(null)"); - ResultSet rs = stmt.executeQuery("select max(identity()) from " + getIncrementerName()); - try { - if (!rs.next()) { - throw new DataAccessResourceFailureException("identity() failed after executing an update"); - } - this.valueCache[i] = rs.getLong(1); - } - finally { - JdbcUtils.closeResultSet(rs); - } - } - long maxValue = this.valueCache[(this.valueCache.length - 1)]; - stmt.executeUpdate("delete from " + getIncrementerName() + " where " + getColumnName() + " < " + maxValue); - } - catch (SQLException ex) { - throw new DataAccessResourceFailureException("Could not obtain identity()", ex); - } - finally { - JdbcUtils.closeStatement(stmt); - DataSourceUtils.releaseConnection(con, getDataSource()); - } - } - return this.valueCache[this.nextValueIndex++]; + protected String getIncrementStatement() { + return "insert into " + getIncrementerName() + " values(null)"; + } + + @Override + protected String getIdentityStatement() { + return "select max(identity()) from " + getIncrementerName(); } } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/SqlServerMaxValueIncrementer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/SqlServerMaxValueIncrementer.java index a864fec5be..c63eea5880 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/SqlServerMaxValueIncrementer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/SqlServerMaxValueIncrementer.java @@ -16,30 +16,21 @@ package org.springframework.jdbc.support.incrementer; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; import javax.sql.DataSource; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.jdbc.datasource.DataSourceUtils; -import org.springframework.jdbc.support.JdbcUtils; - /** * {@link DataFieldMaxValueIncrementer} that increments the maximum value of a given SQL Server table - * with the equivalent of an auto-increment column. Note: If you use this class, your Derby key + * with the equivalent of an auto-increment column. Note: If you use this class, your table key * column should NOT be defined as an IDENTITY column, as the sequence table does the job. * - *
This class is inteded to be used with Microsoft SQL Server. + *
This class is intended to be used with Microsoft SQL Server. * *
The sequence is kept in a table. There should be one sequence table per * table that needs an auto-generated key. * *
Example: * - *
create table tab (id int not null primary key, text varchar(100)) + *create table tab (id int not null primary key, text varchar(100)) * create table tab_sequence (id bigint identity) * insert into tab_sequence default values* @@ -58,16 +49,10 @@ import org.springframework.jdbc.support.JdbcUtils; *Thanks to Preben Nilsson for the suggestion! * * @author Thomas Risberg + * @author Juergen Hoeller * @since 2.5.5 */ -public class SqlServerMaxValueIncrementer extends AbstractColumnMaxValueIncrementer { - - /** The current cache of values */ - private long[] valueCache; - - /** The next id to serve from the value cache */ - private int nextValueIndex = -1; - +public class SqlServerMaxValueIncrementer extends AbstractIdentityColumnMaxValueIncrementer { /** * Default constructor for bean property style usage. @@ -90,45 +75,13 @@ public class SqlServerMaxValueIncrementer extends AbstractColumnMaxValueIncremen @Override - protected synchronized long getNextKey() throws DataAccessException { - if (this.nextValueIndex < 0 || this.nextValueIndex >= getCacheSize()) { - /* - * Need to use straight JDBC code because we need to make sure that the insert and select - * are performed on the same connection (otherwise we can't be sure that @@identity - * returnes the correct value) - */ - Connection con = DataSourceUtils.getConnection(getDataSource()); - Statement stmt = null; - try { - stmt = con.createStatement(); - DataSourceUtils.applyTransactionTimeout(stmt, getDataSource()); - this.valueCache = new long[getCacheSize()]; - this.nextValueIndex = 0; - for (int i = 0; i < getCacheSize(); i++) { - stmt.executeUpdate("insert into " + getIncrementerName() + " default values"); - ResultSet rs = stmt.executeQuery("select @@identity"); - try { - if (!rs.next()) { - throw new DataAccessResourceFailureException("@@identity failed after executing an update"); - } - this.valueCache[i] = rs.getLong(1); - } - finally { - JdbcUtils.closeResultSet(rs); - } - } - long maxValue = this.valueCache[(this.valueCache.length - 1)]; - stmt.executeUpdate("delete from " + getIncrementerName() + " where " + getColumnName() + " < " + maxValue); - } - catch (SQLException ex) { - throw new DataAccessResourceFailureException("Could not increment identity", ex); - } - finally { - JdbcUtils.closeStatement(stmt); - DataSourceUtils.releaseConnection(con, getDataSource()); - } - } - return this.valueCache[this.nextValueIndex++]; + protected String getIncrementStatement() { + return "insert into " + getIncrementerName() + " default values"; + } + + @Override + protected String getIdentityStatement() { + return "select @@identity"; } } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/SybaseMaxValueIncrementer.java b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/SybaseMaxValueIncrementer.java index 6c86bc9435..5131b2945d 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/SybaseMaxValueIncrementer.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/SybaseMaxValueIncrementer.java @@ -16,20 +16,10 @@ package org.springframework.jdbc.support.incrementer; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; import javax.sql.DataSource; -import org.springframework.dao.DataAccessException; -import org.springframework.dao.DataAccessResourceFailureException; -import org.springframework.jdbc.datasource.DataSourceUtils; -import org.springframework.jdbc.support.JdbcUtils; - /** - * {@link DataFieldMaxValueIncrementer} that increments - * the maximum value of a given Sybase SQL Server table + * {@link DataFieldMaxValueIncrementer} that increments the maximum value of a given Sybase table * with the equivalent of an auto-increment column. Note: If you use this class, your table key * column should NOT be defined as an IDENTITY column, as the sequence table does the job. * @@ -40,7 +30,7 @@ import org.springframework.jdbc.support.JdbcUtils; * *
Example: * - *
create table tab (id int not null primary key, text varchar(100)) + *create table tab (id int not null primary key, text varchar(100)) * create table tab_sequence (id bigint identity) * insert into tab_sequence values()* @@ -59,16 +49,10 @@ import org.springframework.jdbc.support.JdbcUtils; *Thanks to Yinwei Liu for the suggestion! * * @author Thomas Risberg + * @author Juergen Hoeller * @since 2.5.5 */ -public class SybaseMaxValueIncrementer extends AbstractColumnMaxValueIncrementer { - - /** The current cache of values */ - private long[] valueCache; - - /** The next id to serve from the value cache */ - private int nextValueIndex = -1; - +public class SybaseMaxValueIncrementer extends AbstractIdentityColumnMaxValueIncrementer { /** * Default constructor for bean property style usage. @@ -91,53 +75,13 @@ public class SybaseMaxValueIncrementer extends AbstractColumnMaxValueIncrementer @Override - protected synchronized long getNextKey() throws DataAccessException { - if (this.nextValueIndex < 0 || this.nextValueIndex >= getCacheSize()) { - /* - * Need to use straight JDBC code because we need to make sure that the insert and select - * are performed on the same connection (otherwise we can't be sure that @@identity - * returnes the correct value) - */ - Connection con = DataSourceUtils.getConnection(getDataSource()); - Statement stmt = null; - try { - stmt = con.createStatement(); - DataSourceUtils.applyTransactionTimeout(stmt, getDataSource()); - this.valueCache = new long[getCacheSize()]; - this.nextValueIndex = 0; - for (int i = 0; i < getCacheSize(); i++) { - stmt.executeUpdate(getIncrementStatement()); - ResultSet rs = stmt.executeQuery("select @@identity"); - try { - if (!rs.next()) { - throw new DataAccessResourceFailureException("@@identity failed after executing an update"); - } - this.valueCache[i] = rs.getLong(1); - } - finally { - JdbcUtils.closeResultSet(rs); - } - } - long maxValue = this.valueCache[(this.valueCache.length - 1)]; - stmt.executeUpdate("delete from " + getIncrementerName() + " where " + getColumnName() + " < " + maxValue); - } - catch (SQLException ex) { - throw new DataAccessResourceFailureException("Could not increment identity", ex); - } - finally { - JdbcUtils.closeStatement(stmt); - DataSourceUtils.releaseConnection(con, getDataSource()); - } - } - return this.valueCache[this.nextValueIndex++]; - } - - /** - * Statement to use to increment the "sequence" value. Can be overridden by subclasses. - * @return the SQL statement to use - */ protected String getIncrementStatement() { return "insert into " + getIncrementerName() + " values()"; } + @Override + protected String getIdentityStatement() { + return "select @@identity"; + } + } diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/support/DataFieldMaxValueIncrementerTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/support/DataFieldMaxValueIncrementerTests.java index b1e021d2e3..f493a74366 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/support/DataFieldMaxValueIncrementerTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/support/DataFieldMaxValueIncrementerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -20,10 +20,10 @@ import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; - import javax.sql.DataSource; import org.junit.Test; + import org.springframework.jdbc.support.incrementer.HsqlMaxValueIncrementer; import org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer; import org.springframework.jdbc.support.incrementer.OracleSequenceMaxValueIncrementer; @@ -39,20 +39,21 @@ import static org.mockito.BDDMockito.*; public class DataFieldMaxValueIncrementerTests { private DataSource dataSource = mock(DataSource.class); + private Connection connection = mock(Connection.class); + private Statement statement = mock(Statement.class); + private ResultSet resultSet = mock(ResultSet.class); + @Test public void testHsqlMaxValueIncrementer() throws SQLException { given(dataSource.getConnection()).willReturn(connection); given(connection.createStatement()).willReturn(statement); - given(statement.executeUpdate("insert into myseq values(null)")).willReturn(1); given(statement.executeQuery("select max(identity()) from myseq")).willReturn(resultSet); given(resultSet.next()).willReturn(true); given(resultSet.getLong(1)).willReturn(0L, 1L, 2L, 3L, 4L, 5L); - given(statement.executeUpdate("delete from myseq where seq < 2")).willReturn(1); - given(statement.executeUpdate("delete from myseq where seq < 5")).willReturn(1); HsqlMaxValueIncrementer incrementer = new HsqlMaxValueIncrementer(); incrementer.setDataSource(dataSource); @@ -67,6 +68,41 @@ public class DataFieldMaxValueIncrementerTests { assertEquals("002", incrementer.nextStringValue()); assertEquals(3, incrementer.nextIntValue()); assertEquals(4, incrementer.nextLongValue()); + + verify(statement, times(6)).executeUpdate("insert into myseq values(null)"); + verify(statement).executeUpdate("delete from myseq where seq < 2"); + verify(statement).executeUpdate("delete from myseq where seq < 5"); + verify(resultSet, times(6)).close(); + verify(statement, times(2)).close(); + verify(connection, times(2)).close(); + } + + @Test + public void testHsqlMaxValueIncrementerWithDeleteSpecificValues() throws SQLException { + given(dataSource.getConnection()).willReturn(connection); + given(connection.createStatement()).willReturn(statement); + given(statement.executeQuery("select max(identity()) from myseq")).willReturn(resultSet); + given(resultSet.next()).willReturn(true); + given(resultSet.getLong(1)).willReturn(0L, 1L, 2L, 3L, 4L, 5L); + + HsqlMaxValueIncrementer incrementer = new HsqlMaxValueIncrementer(); + incrementer.setDataSource(dataSource); + incrementer.setIncrementerName("myseq"); + incrementer.setColumnName("seq"); + incrementer.setCacheSize(3); + incrementer.setPaddingLength(3); + incrementer.setDeleteSpecificValues(true); + incrementer.afterPropertiesSet(); + + assertEquals(0, incrementer.nextIntValue()); + assertEquals(1, incrementer.nextLongValue()); + assertEquals("002", incrementer.nextStringValue()); + assertEquals(3, incrementer.nextIntValue()); + assertEquals(4, incrementer.nextLongValue()); + + verify(statement, times(6)).executeUpdate("insert into myseq values(null)"); + verify(statement).executeUpdate("delete from myseq where seq in (-1, 0, 1)"); + verify(statement).executeUpdate("delete from myseq where seq in (2, 3, 4)"); verify(resultSet, times(6)).close(); verify(statement, times(2)).close(); verify(connection, times(2)).close(); @@ -76,7 +112,6 @@ public class DataFieldMaxValueIncrementerTests { public void testMySQLMaxValueIncrementer() throws SQLException { given(dataSource.getConnection()).willReturn(connection); given(connection.createStatement()).willReturn(statement); - given(statement.executeUpdate("update myseq set seq = last_insert_id(seq + 2)")).willReturn(1); given(statement.executeQuery("select last_insert_id()")).willReturn(resultSet); given(resultSet.next()).willReturn(true); given(resultSet.getLong(1)).willReturn(2L, 4L); @@ -94,6 +129,7 @@ public class DataFieldMaxValueIncrementerTests { assertEquals("3", incrementer.nextStringValue()); assertEquals(4, incrementer.nextLongValue()); + verify(statement, times(2)).executeUpdate("update myseq set seq = last_insert_id(seq + 2)"); verify(resultSet, times(2)).close(); verify(statement, times(2)).close(); verify(connection, times(2)).close();