JDBC – Emulating a sequence
Probably each of us encountered this problem at least once in the programmer’s life – how to emulate a database sequence? Below you may find my variation of this problem’s solution.
Suppose that we have an interface defining the desired API for returning a sequence of integer numbers:
1 2 3 4 5 | public interface Sequences { int nextValue(String sequenceName) throws SQLException;} |
and the implementation of this API in the following form:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | class SequencesService implements Sequences { private static final String SQL_QUERY = "SELECT SEQ_NAME, SEQ_VALUE FROM SEQUENCE WHERE SEQ_NAME = ? FOR UPDATE"; private final DataSource dataSource; SequencesService(final DataSource dataSource) { this.dataSource = dataSource; } @Override public int nextValue(final String sequenceName) throws SQLException { final long threadId = Thread.currentThread().getId(); try (final Connection connection = dataSource.getConnection()) { connection.setAutoCommit(false); try (final PreparedStatement statement = connection.prepareStatement( SQL_QUERY, TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE)) { statement.setString(1, sequenceName); try (final ResultSet resultSet = statement.executeQuery()) { System.out.println( String.format("[%d] - select for update", threadId)); int nextValue = 1; if (resultSet.next()) { nextValue = 1 + resultSet.getInt(2); resultSet.updateInt(2, nextValue); resultSet.updateRow(); } else { resultSet.moveToInsertRow(); resultSet.updateString(1, sequenceName); resultSet.updateInt(2, nextValue); resultSet.insertRow(); } System.out.println( String.format("[%d] - next val: %d", threadId, nextValue)); return nextValue; } } finally { System.out.println(String.format("[%d] - commit", threadId)); connection.commit(); } } }} |
You have to forgive me two things :) – the println usage, which I added for generating some visual feedback ;) and a lack of detailed explanation how this solution works ;) I’ll just mention that the clue is the way prepared statement is created, and the result set handling: updateRow / moveToInsertRow / insertRow usage ;) (see the links at the bottom of this post for the details).
I wrote simple test case to observe and verify this code, something like:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | @Autowiredprivate Sequences sequences;private Callable<Integer> callable() { return () -> { System.out.println(String.format("[%d] - starting", Thread.currentThread().getId())); return sequences.nextValue("My Sequence"); };}@Testpublic void test() throws Exception { final ExecutorService executor = Executors.newFixedThreadPool(3); final CompletionService<Integer> completion = new ExecutorCompletionService<>(executor); for (int i = 0; i < 3; i++) { completion.submit(callable()); } for (int completed = 1; completed <= 3; completed++) { final Future<Integer> result = completion.take(); System.out.println(String.format("Result %d - %d", completed, result.get())); assertEquals(Integer.valueOf(completed), result.get()); }} |
When run, the above code, the output will be something like this (threads’ IDs in the brackets):
[16] – starting
[18] – starting
[17] – starting
[17] – select for update
[17] – next val: 1
[17] – commit
[18] – select for update
Result 1 – 1
[18] – next val: 2
[18] – commit
[16] – select for update
[16] – next val: 3
[16] – commit
Result 2 – 2
Result 3 – 3
This code is just for demonstration purposes :) – if you want to do something similar in your project, it’s probable that you will rather use for ex. Spring Framework’s @Transactional annotation, instead of manual transactions handling, or even JPA delegating this work to JDBC. For example in Hibernate you may do it somehow like this:
1 2 3 4 5 | import org.hibernate.Session;...entityManager.unwrap(Session.class) .doReturningWork(connection -> { ... code derived from my example ... }); |
Few links for the dessert:
- Updating Rows in ResultSet Objects (JDBC)
- Inserting Rows in ResultSet Objects (JDBC)
- Declarative transaction management and Using @Transactional (Spring Framework)
- ReturningWork (JPA, Hibernate)
… and I almost forgot ;) – GitHub repository holding all my code expriments for this post
Published on Java Code Geeks with permission by Michal Jastak, partner at our JCG program. See the original article here: JDBC – Emulating a sequence Opinions expressed by Java Code Geeks contributors are their own. |

