Let's say I have a mapped User object with a user_id as a primary key, and a mail column with a unique constraint. I want my program to save a User object to the users table only if it doesn't exist.
I can do the following thing in my insert function:
- begin transaction
- query for a user with the given mail
- if it doesn't exist, create a new user and save it using the session
- commit or rollback if failed
There are two problems:
- It's expensive to perform two queries. If I was using plain SQL I might use "INSERT IGNORE" syntax, but in my case I want to use hibernate save method, and also I want to hold the User object in the end. Is there a solution for it?
- Concurrency. Is it possible that two instances of my application will run at the same time. Both will use the "addUser" function with the same "mail" parameter. The first will go through phase 2 and won't find a user with that mail. The second will also go through phase 2 without finding a user because the first instance still didn't save his user and commited. Then the first instance will save and commit the user, and afterwards the second instance will save and commit the user, which has the same mail as the first instance's mail. Of course it will fail, because of the constraint. Am I missing something?
If I am right what should I do:
- Hope that it won't happen.
- Lock the users table for read and write at the beginning of the transaction.
- Add try...except to the function, that will except a unique constraint exception, and if the exception is thrown, will just select the user from the db according to its mail.
- Other solutions...