-->
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.  [ 7 posts ] 
Author Message
 Post subject: Problem with hibernate pessimistic locking...
PostPosted: Fri Nov 25, 2005 11:34 am 
Newbie

Joined: Fri Nov 25, 2005 11:24 am
Posts: 4
I got problem with hibernate pessimistic locking:

exp:
Code:

public class Account {
   private Long id;
   private String user;
   private int balance;
   ...
}

public class AccountManager {
   public static void deposit(long id){
      try{
         Session session = HibernateUtil.getInstance().currentSession();
         Transaction tx = session.beginTransaction();
         Account account = (Account)session.get(Account.class, id, LockMode.UPGRADE);
         account.setBalance(account.getBalance() + 1);
         System.out.println("Get balance is: " + account.getBalance());
         tx.commit();
         HibernateUtil.getInstance().closeSession();
      }catch(Exception e){
         e.printStackTrace();
      }
   }
}

public class UserThread extends Thread{
   private final static long USER_ID = 1;
   private String threadId;
   
   public void setThreadId(String id){
      threadId = id;
   }
   public void run(){
      for(int i=0;i<100;i++){
         AccountManager.deposit(USER_ID);
         System.out.println("Thread: [" + threadId + "]" + "updata successfully -- " + "[" + System.currentTimeMillis() + "]" );
         try{
            sleep(10);
         }catch(Exception e){
            e.printStackTrace();
         }
      }
   }
}


the log is like:
Code:
.......
.......
.......
Get balance is: 57
Hibernate: update account set user=?, balance=? where id=?
Thread: [Thread B ]updata successfully -- [1132931577687]
Hibernate: select account0_.id as id0_, account0_.user as user2_0_, account0_.balance as balance2_0_ from account account0_ where account0_.id=? for update
Get balance is: 58
Hibernate: update account set user=?, balance=? where id=?
Thread: [Thread B ]updata successfully -- [1132931577703]
Hibernate: select account0_.id as id0_, account0_.user as user2_0_, account0_.balance as balance2_0_ from account account0_ where account0_.id=? for update
Hibernate: select account0_.id as id0_, account0_.user as user3_0_, account0_.balance as balance3_0_ from account account0_ where account0_.id=? for update

Get balance is: 59
Get balance is: 59
Hibernate: update account set user=?, balance=? where id=?
Hibernate: update account set user=?, balance=? where id=?
Thread: [Thread A ]updata successfully -- [1132931577750]
Thread: [Thread B ]updata successfully -- [1132931577750]

Hibernate: select account0_.id as id0_, account0_.user as user3_0_, account0_.balance as balance3_0_ from account account0_ where account0_.id=? for update
Get balance is: 60
Hibernate: update account set user=?, balance=? where id=?
Thread: [Thread A ]updata successfully -- [1132931577750]
Hibernate: select account0_.id as id0_, account0_.user as user3_0_, account0_.balance as balance3_0_ from account account0_ where account0_.id=? for update
Get balance is: 61
....
....
....



I used two threads to update one account record, as described above, while both thread finish, this account balance will increase to 200. but somehow, the value increased will be less than 200, it will be 198,197. I don't know what's wrong with the pessimistic locking. Any body can tell me? Thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 25, 2005 2:36 pm 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
it can be a problem with data type convertion ("200" to "198,197") and make sure "autocommit" is dissabled if you calculate stuff this way, but if this is "real world" use case then it must be better to implement "deposit" this way: "update account set balance= balance + ? where id=?".

"insert into transfer (account,widraw,depost) values (?,?,?)" is more typical in financial applications (balance is "select sum(widraw - depost) as balance from transfer where account = ?"), it doe's not lose information about transfer.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 25, 2005 10:45 pm 
Newbie

Joined: Fri Nov 25, 2005 11:24 am
Posts: 4
dear baliukas:
I setAutoCommit(false), but still can not resolve this problem. The program is not used in "real world", just a example to describe my problem. I am not very clear about your "data type convertion ("200" to "198,197") ", but I think my problem is that at one time, there are two threads access the one database record, just as the log shows:

Code:
....
....
Get balance is: 59
Get balance is: 59
Hibernate: update account set user=?, balance=? where id=?
Hibernate: update account set user=?, balance=? where id=?
Thread: [Thread A ]updata successfully -- [1132931577750]
Thread: [Thread B ]updata successfully -- [1132931577750]
....
....


So, dose it means the pessimistic locking invalidity?


Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 26, 2005 5:15 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
try to use "decimal" or "numeric", it can be a rounding error if you use "double" or "float" as field type.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 26, 2005 5:20 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
BTW you do not need locking for this use case, correct value will be calculated if isolation level is "serializable"


Top
 Profile  
 
 Post subject: Try InnoDB
PostPosted: Sat Nov 26, 2005 12:13 pm 
Newbie

Joined: Fri Nov 25, 2005 12:08 pm
Posts: 1
Hi lemonelei,

Have you set your DB table type to InnoDB?


Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 26, 2005 12:24 pm 
Newbie

Joined: Fri Nov 25, 2005 11:24 am
Posts: 4
Hi qianjinstug:
Oh,ye, it works.

InnoDB provides MySQL with a transaction-safe (ACID compliant) storage engine with commit, rollback, and crash recovery capabilities. InnoDB does locking on the row level and also provides an Oracle-style consistent non-locking read in SELECT statements. These features increase multi-user concurrency and performance. There is no need for lock escalation in InnoDB because row-level locks in InnoDB fit in very little space. InnoDB also supports FOREIGN KEY constraints. In SQL queries you can freely mix InnoDB type tables with other table types of MySQL, even within the same query.


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