Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Locking Potential Transactions in PostgreSQL

Well, Sorry, if you find this question weird, But Let me ask It anyway.
Imagine the following situation. There is 2 Clients, A and B. The A Client decided to create Profile and the Transaction in general takes 2 Minutes until Completion for example.

After 1 minute, B Client Decided to create a Profile with THE SAME Username And Password, (but the first Transaction is still in the Process, And we cannot apply the unique constraint, because there is no such User with this Username quite yet.)

So It will eventually end up with UNIQUE CONSTRAINT exception, and we’ll need to make a rollback.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

The Question is: How to avoid this situation?

I’ve heard about LOCK in PostgreSQL (that allows to lock the EXISTING ROW in order to others can’t change it or read) but haven’t find any similar to this sort of case.

Is there any feature, that provides some sort of functionality to block potential transactions?

>Solution :

The Question is: How to avoid this situation?

A simple way would be to split the commit into two parts, probably using a savepoint:

func createUser(user: User) error {
    this.db.exec('INSERT INTO users VALUES ($1, $2)', user.username, user.hashedPassword);
    this.db.withTransaction(func (tx Transaction) {
        tx.exec('DELETE FROM users WHERE username = $1', user.username);
        sp = tx.createSavepoint();
        tx.exec('INSERT INTO users VALUES ($1, $2)', user.username, user.hashedPassword);
        try {
            // your code that takes two minutes
            tx.commit();
        } catch (e) {
            tx.rollbackToSavepoint(sp);
            tx.commit();
        }           
    });
}

Where you first insert your row, immediately commiting the change. Now any new user can’t use that username.

Then, start a transaction, delete the user. Create a savepoint. Create the user again. Now, instead of rolling back the entire transaction if something fails, rollback to the savepoint (where the user was created then deleted, effectively a no-op). If it works, since you deleted then created again, then the delete was effectively a no-op.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading