-->
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.  [ 8 posts ] 
Author Message
 Post subject: Atomic operations
PostPosted: Fri Oct 22, 2004 1:03 am 
Newbie

Joined: Thu Sep 23, 2004 4:11 am
Posts: 12
Location: Gold Coast, Australia
Hibernate version: 2.0

Suppose I have an entity called 'Account' with a primary key field 'username'. Now, a user wants to create an 'Account' so they submit their preferred username, say "Fred".

How do I check if "Fred" exists, and if it doesn't, insert (Session.save) the Account?

For example, consider the following code:

Code:
tx = session.beginTransaction();

if(session.get(Account.class, "Fred") != null)
{
    tx.commit();
    // tell the user that this account username already exists
}
else
{
    Account a = new Account();
    session.save(a, "Fred");
    tx.commit();
}


I'm not sure how close this is to being correct, but I know that if two concurrent users are executing this code, there is potential for a race condition. If "Fred" doesn't exist, then user1 executes up to the point where the Account instance is created, then user2 executes, who also gets into the 'else block' - one of them will fail with a primary key violation.

So the question is, how do I achieve what I want to achieve - that is check if the account exists and if it doesn't, create that account; all in one atomic operation?

_________________
SCJP 1.4, SCJD
Software Engineer, IBM Australia


Top
 Profile  
 
 Post subject: Atomicity
PostPosted: Fri Oct 22, 2004 2:27 am 
Newbie

Joined: Thu Sep 23, 2004 4:11 am
Posts: 12
Location: Gold Coast, Australia
Another way to summarise my problem is "is it possible to obtain exclusive INSERT access on an entity?"

_________________
SCJP 1.4, SCJD
Software Engineer, IBM Australia


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 22, 2004 10:47 am 
Regular
Regular

Joined: Tue Sep 28, 2004 6:34 pm
Posts: 50
You could lock the table, but I do not think that it is a good idea.

You can also try to catch the pk violation exception and if caught re-read:

Code:
        boolean caughtPKException = false;
        Session sess = factory.openSession();
        Transaction tx;
        try {
           tx = session.beginTransaction();
           if(session.get(Account.class, "Fred") == null) {
              Account a = new Account();
              session.save(a, "Fred");
           }
           tx.commit();
        } catch (??PK validation/duplicate /*
                                          * don't know exact name just insert
                                          * the same object twice to get it
                                          */??Exception e) {
            if (tx!=null) tx.rollback();
            caughtPKException = true;
        } finally {
            sess.close();
        }
       if (caughtPKException) {
          /*must obtain new session: [quote]If the Session throws an exception, the transaction must be rolled back and the session discarded. The internal state of the Session might not be consistent with the database after the exception occurs. [/quote]*/
           Session sess = factory.openSession();
           tx = session.beginTransaction();
           if(session.get(Account.class, "Fred") == null) {
              //this should not happen
           }
           tx.commit();
       }


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 22, 2004 10:51 am 
Newbie

Joined: Tue Jul 06, 2004 9:56 am
Posts: 14
If your DB transaction level is serializable, your code should work out of the box, since your read and (possible) write operations are in the same transaction.


Top
 Profile  
 
 Post subject: Atomic operations
PostPosted: Fri Oct 22, 2004 8:24 pm 
Newbie

Joined: Thu Sep 23, 2004 4:11 am
Posts: 12
Location: Gold Coast, Australia
Thanks for the reply.
I'm unsure what you mean by my "DB transaction level is serializable".
How can I tell? What document would I read to understand the concept?

I found the following code in the reference manual 9.2, which is exactly what I want, so it can't be too difficult to achieve in a concurrent environment.

I tried executing similar code from within a debugger using two concurrent users - after user1, I put a break within the statement block after the check for null. A subsequent execution of the code was also allowed to enter the statement block, which gave the idea that there needs to be some concurrency control - am I mistaken?

Code:
Cat cat = (Cat) sess.get(Cat.class, id);
if (cat==null) {
    cat = new Cat();
    sess.save(cat, id);
}
return cat;
[/code]

_________________
SCJP 1.4, SCJD
Software Engineer, IBM Australia


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 22, 2004 9:09 pm 
Regular
Regular

Joined: Tue Sep 28, 2004 6:34 pm
Posts: 50
A few things:

A)
Quote:
serialization at the transaction level - This means that every statement within a transaction will get the same consistent view of data as it existed at the start of the transaction.


B) you can use java's synchronized blocks to block threads

C) why do you want to use name as primary key - this seams wired - what if user changes name and you have relations with this pk?

Lukasz


Top
 Profile  
 
 Post subject: Atomic operations
PostPosted: Fri Oct 22, 2004 9:21 pm 
Newbie

Joined: Thu Sep 23, 2004 4:11 am
Posts: 12
Location: Gold Coast, Australia
A)serialization at the transaction level - This means that every statement within a transaction will get the same consistent view of data as it existed at the start of the transaction.

Ok thanks - understood.

B) you can use java's synchronized blocks to block threads

Right - I assume this is what I want.

C) why do you want to use name as primary key - this seams wired - what if user changes name and you have relations with this pk?

An account is defined by the username. A user can delete an account or create a new one; the only alternative is to create an id for the Account entity and make username unique - which still has the same problem - but a user can change their username (if it doesn't exist), so it might be a better option.

_________________
SCJP 1.4, SCJD
Software Engineer, IBM Australia


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 22, 2004 10:39 pm 
Regular
Regular

Joined: Tue Sep 28, 2004 6:34 pm
Posts: 50
if you need something more related to user and unique than use email (it is more likely to be unique) and use integer as pk.

Lukasz


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 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.