Search code examples
sqlpostgresqlormlockingdistributed

Distributed locking vs constraint violation exception handling for control flow


I have a distributed system that needs to perform an atomic database operation. In essence, the application needs to perform a find or create.

I can think of two options:

A) Use a distributed lock to ensure that the operation is atomic across processes/systems. Check if the record exists. Get or create the record accordingly.

B) Always attempt to insert the record. Allow the database to raise a unique constraint violation error and catch the exception in the application. If an exception is raised, then it exists so get the record instead.

Option A seems more correct obviously but which is more performant?

Using exception handling for control flow is smelly but is it really that terrible? I feel like option B is more readable and easier to reason about. Plus it doesn't require a lock on the database.

Can you anyone give me a concrete reason not to use option B with concrete evidence?

Thanks!


Solution

  • Locks obviously come at a cost; even if your processes don't block while trying to acquire them, they still take time and resources to manage.

    As far as I know, raising an exception has no consequences, provided it doesn't trigger a rollback of some previously-inserted data (bloating your tables and creating work for the autovacuum).

    But as of Postgres 9.5, you can do the same thing - without the smell - using an INSERT ... ON CONFLICT DO NOTHING statement. Your client library should return the number of affected rows, which will tell you whether or not the INSERT succeeded.