> > Simply put if there's $5 left in the bank, you wouldn't want to have
> > a user withdraw $5 with two different web browsers if they hit
> > submit at the same time... so we kinda want it to be like there's
> > only one teller window, and the servlets have to wait their
> > turn.

A poster already mentioned that simplistic solutions might not work
in a clustered environment.  I agree that designs that work due
to timing or happen stance that may not remain constant are weak 
designs bound to have problems in deployment.

This problem is the the classic stale update scenario.  Multiple
clients show $5 available to with draw.  They all hit "submit"
at once.  How to guard against an over draft in a robust and 
repeatable in all scenarios way??

The most offered solution that I've heard and I've implemented uses
optimistic concurrancy guarded with a row version number;

- add a version number or modification date to your data base tables.
  I use a sequence number that trigger auto-increaments on update.

- Your Model class (represents a data base table row) returned by 
  DAO's and Entities include the sequence number.

- Your presentation tier has a reference of the model (including the 
  row version number)  and all display $5 and internally held in
  the session is an instance of the Model used to generate the 
  dynamic data by your View (MVC) component.

- All users hit submit.

- The Controller (MVC) processing this event fetches the Model from
  the session and calls the setter to modify withdraw ammount, passes
  this Model to the Business Deligate to access your transactional layer
  (mediated by a Session bean calling Entities).

- The Model instance is serialized and passed as an argument to the
  layers of business components down to the Entity responsible for
  updating the AccountBalance table row for this account.

- I used BMP and DAO objects to package the SQL logic.  My DAO fetches
  the sequence number from the Model and account new balance from the
  model and builds the SQL prepared statement:

  UPDATE account set balance = ? where column_version_num = ? ;

  I call stment.setString (1, model.getNewBalance());
         stment.setString (2, model.getVersionNumber());

  If I get a SQLException on this update, then I know that someone else
  beat me to the $5.

  The key concept is the WHERE clause will only update the row IFF
  the sequence number has not been changed by someone else (meaning
  I had stale data).


This will work in clustered environments at all times and does not
depend on synchronized business delegate methods or any other design
that is likely to be defeated by appserver servlet or object pooling
or use of multiple VMs to host your application. 

Good luck,

curt



Reply via email to