title: concurrency in hibernate
body: <p>I have a servlet that does some work for user and then decrement user's credit. When I watch user's credit in the database in real time, if there are many concurrent requests from the same user, the credit has been deducted incorrectly due to concurrency control.  T
  Assume I have one server and database management used is hibernate.
  I am using transaction control to span the whole request, please see code for detail.  I have several questions:</p>
  
  <ol>
  <li><p>Why are the credit counter in db jumping all over the place when facing many concurrent request from same user?  why isn't my transaction control working?</p></li>
  <li><p>If underlying data was modified after I retrieved user account and then attempt to update it, why didn't I get any <code>HibernateException(eg.StaleObjectException)</code>?</p></li>
  <li><p>I have transaction span across the full user request, is there a better way?  Please critique. Feel free to rewrite the sample code structure if you feel I'm doing the whole thing wrong.</p></li>
  </ol>
  
  <pre>
  Main servlet class:
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  
              try{
                  Manager.beginTransaction();
                  cmdDowork(request, response);
                  Manager.commitTransaction();
              }catch(Exception exp){
                  Manager.rollbackTransaction();
                  exp.printStackTrace();
              }
              finally{
                  Manager.closeSession();
              }
  }
  
  public void cmdDowork(){
  try{
       UserAccount userAccount = lazyGetUserAccount(request.getParameter("userName"));
  
       doWorkForUser(userAccount);//time and resource consuming process
  
       if(userAccount!=null) {
  
      decUserAccountQuota(userAccount);
  
       }
  
  }catch (HibernateException e){
      e.printStackTrace();
  
  }
  }
  
  public static UserAccount lazyGetUserAccount(String userName) {
          UserAccount userAccount = Manager.getUserAccount(userName);
          if(userAccount == null){
              userAccount = new UserAccount(userName);
              userAccount.setReserve(DEFAULT_USER_QUOTA);
              userAccount.setBalance(DEFAULT_USER_QUOTA);
              Manager.saveUserAccount(userAccount);
          }
       return userAccount;
  }
      private boolean decUserAccountQuota(UserAccount userAccount) {
  
          if(userAccount.getBalance() 
  
  <p>Edit: code I used to test optimistic locking as suggested by the answer, I am not getting a
  any StaleObjectException, the update were committed successfully..
  
  Session em1=Manager.sessionFactory.openSession();
           Session em2=Manager.sessionFactory.openSession();</p>
  
  <code>    em1.getTransaction().begin();
      em2.getTransaction().begin();
      UserAccount c1 = (UserAccount)em1.get( UserAccount.class, "jonathan" );
      UserAccount c2 = (UserAccount)em2.get( UserAccount.class, "jonathan" );
      c1.setBalance( c1.getBalance() -1 );
      em1.flush();
      em1.getTransaction().commit();
  
  
  
  
  
  
      System.out.println("balance1 is "+c2.getBalance());
      c2.setBalance( c2.getBalance() -1 );
      em2.flush(); // fail
      em2.getTransaction().commit();
  
      System.out.println("balance2 is "+c2.getBalance());
  </code></pre>