-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: Unique columns, "race condition"
PostPosted: Sat Dec 29, 2007 7:29 am 
Newbie

Joined: Sat Oct 28, 2006 3:05 pm
Posts: 10
Hi everyone.
I have the following situation: suppose I have an application that allows users to register if they don't have an account yet. The form takes the new user's login and password, and passes that to a method in an instance of a stateful session bean (User is an entity, and the specs state login should be unique accross the whole system):
Code:
User currentUser = ... // create the current instance based on the form input
//this was passed with the @In annotation from Seam in the original listing
...
public String doRegister() {
    List existing = em.createQuery("select u.username from User u where u.username = :login").setParameter("login", currentUser.getUsername())
.getResultList();
    if (existing.size() != 0) {
        facesMessages.add("User exists!");
        return null;
    } else {
        em.persist(currentUser);
        facesMessages.add("Registration complete.");
        return "login";
    }
}

(The above listing originates from listing 17.16, "Java Persistance with Hibernate"- a great book by the way, thanks for that guys!)

Suppose two new users are simultanously trying to register, with the same login. What happens is:
1. user A calls this method, and there is not a user with this login
2. user hasn't pressed the OK button that would create the new account
3. now user B calls the same method, and there still is no user with the login they chose, so everyone is happy
4. now user A commits the transaction, persisting the new User instance
5. user B tries to commit the transaction, but this time the login already exists (user A was there first)!

What we have now is that there are two users with the same login, which violates the rule. If we add a unique constraint on the LOGIN column, user B will get an exception of some type.

Is this what should happen? I mean, maybe Hibernate gives another, more elegant, solution? How should situations like that be dealt with? Some locks or something? But locking would prevent others from registering if user A went for lunch.

Thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Dec 29, 2007 10:56 am 
Regular
Regular

Joined: Sat Nov 25, 2006 11:37 am
Posts: 72
I would think that a unique constraint on the username column is the best solution. You most likely cannot rely on the database transaction handling to catch this unless you set the TRANSACTION ISOLATION LEVEL to SERIALIZABLE because what you are dealing with here is the so called 'phantom problem', that is a row materializing that wasn't there at the beginning. Should you you go with the SERIALIZABLE isolation level be prepared to deal with db initiated transaction rollbacks because of deadlocks (if you have a locking db system) or version conflicts (if you have an optimistic concurrency control db system).


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.