Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 531009
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 13, 20262026-05-13T09:15:23+00:00 2026-05-13T09:15:23+00:00

I have a servlet that does some work for user and then decrement user’s

  • 0

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:

  1. 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?

  2. If underlying data was modified after I retrieved user account and then attempt to update it, why didn’t I get any HibernateException(eg.StaleObjectException)?

  3. 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.

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() 

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();

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());
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-13T09:15:23+00:00Added an answer on May 13, 2026 at 9:15 am

    You have two ways to handle this situation: either with pessimist locking or with optimist locking. But you seem to use neither of both, which explain probably the incorrect behaviour.

    • With optimistic locking, Hibernate will check that the user account wasn’t altered between the time it was read and saved. A concurrent transaction may then fail and be rolled back.

    • With pessimistic locking, you lock the row when you read it and it’s unlocked only when transaction completes. This prevent a concurrent transaction to read data that would become stale.

    Refreshing the entity may read new data or not depending whether the current transaction has already been committed or not, but is not a solution neither. Because you seem to also create the user account if it doesn’t exist, you can’t apply pessimist locking so easily. I would suggest you use optimistic locking then (and use for instance a timestamp to detect concurrent modifications).

    Read this other question on SO about pessimist and optimist locking. Have also a look at hibernate chapter “transaction and concurrency” and “hibernate annotations“.

    It should be as simple as adding @Version on the corresponding field, the optimisticLockStrategy default value is VERSION (a separate column is used).

    — UPDATE —

    You can test whether it works in a test case. I’ve created a simple entity Counter with an ID, value, and version fields.

     public class Counter implements Serializable {
    
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        @Basic(optional = false)
        @Column(name = "ID")
        private Integer id;
    
        @Column(name = "VALUE")
        private Integer value;
    
        @Column(name = "VERSION")
        @Version
        private Integer version;
        ...
    }
    

    If you update one entity sequentially it works:

      id = insertEntity( ... );
    
      em1.getTransaction().begin();               
      Counter c1 = em1.find( Counter.class, id );                
      c1.setValue( c1.getValue() + 1 );
      em1.flush();
      em1.getTransaction().commit();
    
    
      em2.getTransaction().begin();
      Counter c2 = em2.find( Counter.class, id );
      c2.setValue( c2.getValue() + 1 );
      em2.flush(); // OK
      em2.getTransaction().commit(); 
    

    I get one entity with value=2 and version=2.

    If I simulate two concurrent updates:

    id = insertEntity( ... );
    
    em1.getTransaction().begin();
    em2.getTransaction().begin();
    
    Counter c1 = em1.find( Counter.class, id );
    Counter c2 = em2.find( Counter.class, id );
    
    c1.setValue( c1.getValue() + 1 );
    em1.flush();    
    em1.getTransaction().commit();
    
    c2.setValue( c2.getValue() + 1 );
    em2.flush(); // fail    
    em2.getTransaction().commit();
    

    then the 2nd flush fails:

    Hibernate: update COUNTER set VALUE=?, VERSION=? where ID=? and VERSION=?
    Hibernate: update COUNTER set VALUE=?, VERSION=? where ID=? and VERSION=?
    Dec 23, 2009 11:08:46 AM org.hibernate.event.def.AbstractFlushingEventListener performExecutions
    SEVERE: Could not synchronize database state with session
    org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [org.ewe.Counter#15]
            at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1765)
    

    This is so because the actual parameters in the SQL statements are:

       update COUNTER set VALUE=1, VERSION=1 where ID=xxx and VERSION=0   
       --> 1 row updated
       update COUNTER set VALUE=1, VERSION=1 where ID=xxx and VERSION=0   
       --> 0 row updated, because version has been changed in between
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have a class that acts as a manager and does some work. A
I have an application that uses html5 to let the user listen to some
I have servlet that does the following: public class LoginServlet extends HttpServlet { protected
I have a servlet that does a request dispatcher include of another servlet. The
I have a servlet that is used for many different actions, used in the
I have a servlet that I would like to run within ColdFusion MX 7.
I have a file upload form that is being posted back to a servlet
I have a servlet running in an Oracle OCCAS server. Currently I map some
I have a simple jasper report that does not need a datasource so I
I have a script that appends some rows to a table. One of the

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.