1

We have a code that inserts a new value into the table column that is a primary key. First we are doing select and if this value is not present then we do insert.

query = "SELECT AValue from ATableCache WHERE AValue=" + avalue;
ResultSet rs = stmt.executeQuery(query);
if (!rs.next()) 
{
    query = "INSERT INTO ATableCache (AValue) VALUES ('" + avalue + "')";
    stmt.executeUpdate(query);
}

At race conditions this algorithm can result in an SQL error while inserting a value that was just inserted by another thread. One of the options is synchronization but this will slow execution. Please, note that insertion happens quite seldom. Is there more efficient algorithm?

Alex
  • 7,007
  • 18
  • 69
  • 114

5 Answers5

3

I'd have the database generate the key and make sure that the transaction is serializable. You need to set the isolation level on your database connection properly.

It might be possible to do with PostgreSQL, but a general solution guaranteed to work for all JDBC drivers has eluded Spring, according to this answer:

Is there anyway to get the generated keys when using Spring JDBC batchUpdate?

Community
  • 1
  • 1
duffymo
  • 305,152
  • 44
  • 369
  • 561
2
query = "INSERT INTO ATableCache (AValue) select '" + avalue +
"' where not exists (select 1 from ATableCache where AValue = '"+avalue +"')";
Panos Theof
  • 1,450
  • 1
  • 21
  • 27
1

There aren't that many options:

  1. Your avalue generation code will need to create unique keys atomically. This will require synchronization so that the value isn't shared by threads.

  2. Let the database handle generating the key.

  3. Catch the exception and handle it (not recommended).

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
0

I saw the tag postgresql in your post. In this case, I suggest you to set your primary key autogenerated and note put it in your insert statement.

I think this post can help if you try this approach.

Community
  • 1
  • 1
0

Postgresql uses sequences for key generation or you can use the serial data type.

For sequences it is straightforward and here are the docs: http://www.postgresql.org/docs/8.1/static/sql-createsequence.html. The downside is you need to use nextval() on your inserts, but you get features like being able to pick how many values to cache.

Your other option is to set your primary key to one of the serial types. The docs and a good link on the ins and outs of serial.

Serial will create the primary key without you needing to specify it in your insert.

Erik Nedwidek
  • 6,134
  • 1
  • 25
  • 25