I am working on a multithreaded application that uses DB2 for its primary database. In the past we've mostly used Identity columns for tables where we needed an auto-generated unique identifier. To do that we would run the below 2 queries in the same transaction:
INSERT INTO tbname (IDENTITY_COL, ...) VALUES (DEFAULT, ...);
SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1;
We are now being pressured to switch to Sequence instead. I know you can use "NEXT VALUE FOR colname" in both INSERT and SELECT statements, but I can't figure out how to both INSERT and SELECT with the same value without risking a race condition in a multithreaded application. For example, if I use:
INSERT INTO tbname (SEQUENCE_COL, ...) VALUES (NEXT VALUE FOR SEQUENCE_COL, ...);
SELECT PREVIOUS VALUE FOR SEQUENCE_COL;
Then there's a possibility another INSERT was run between the above INSERT and SELECT, hence providing me the incorrect value. If I try:
SELECT NEXT VALUE FOR SEQUENCE_COL;
store the value in a variable and pass that in to the INSERT:
INSERT INTO tbname (SEQUENCE_COL, ...) VALUES (variable_value, ...);
Then there's a possibility another thread got the same NEXT VALUE and tries to insert the same value, resulting in a DB2 -803 error. Is it possible to use SEQUENCE columns in a multithreaded environment, or do I need to fight to keep my IDENTITY columns?
You can access the value of a sequence using the NEXTVAL or CURRVAL operators in SQL statements. You must qualify NEXTVAL or CURRVAL with the name (or synonym) of a sequence object that exists in the same database, using the format sequence. NEXTVAL or sequence.
A sequence is a user-defined object that generates a sequence of numeric values according to the specification with which the sequence was created. Sequences, unlike identity columns, are not associated with tables. Applications refer to a sequence object to get its current or next value.
The DB2 Drop Sequence Tool allows users to select a sequenceSequence to be dropped. The tool then generates the SQL to drop the sequence. Listed below is an example SQL statement generated by the Drop Sequence Tool.
In addition to what Michael Sharek (correctly) said:
INSERT INTO tbname (SEQUENCE_COL, ...) VALUES (NEXT VALUE FOR SEQUENCE_COL, ...);
SELECT PREVIOUS VALUE FOR SEQUENCE_COL;
Your assumption Then there's a possibility another INSERT was run between the above INSERT and SELECT, hence providing me the incorrect value" regarding the above sequence of statements is incorrect.
The "next value" and "previous value" are connection specific.
Access to a sequence from different threads will never create a "race" condition. Each connection has a completely isolated "environment" for the sequence.
You've got a mistaken assumption in your question.
If I try:
SELECT NEXT VALUE FOR SEQUENCE_COL;
store the value in a variable and pass that in to the INSERT:
INSERT INTO tbname (SEQUENCE_COL, ...) VALUES (variable_value, ...);
Then there's a possibility another thread got the same NEXT VALUE and tries to insert the same value
That's not correct. The second thread would get a different NEXTVAL and not the same value as the first thread.
I also want to add my opinion on this part:
We are now being pressured to switch to Sequence instead.
I can't imagine there being a really good reason to switch to sequences from identity. They're basically the same thing.
In addition to the other correct answers, you can also just use a single statement to insert a row and return inserted values as follows:
SELECT SEQUENCE_COL FROM NEW TABLE (
INSERT INTO tbname (SEQUENCE_COL, ...) VALUES (NEXT VALUE FOR MY_SEQUENCE, ...)
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With