views:

551

answers:

4

I have a ASP.NET C# business webapp that is used internally. One issue we are running into as we've grown is that the original design did not account for concurrency checking - so now multiple users are accessing the same data and overwriting other users changes. So my question is - for webapps do people usually use a pessimistic or optimistic concurrency system? What drives the preference to use one over another and what are some of the design considerations to take into account?

I'm currently leaning towards an optimistic concurrency check since it seems more forgiving, but I'm concerned about the potential for multiple changes being made that would be in contradiction to each other.

Thanks!

A: 

I assume you're experiencing the 'lost update' problem.

To counter this as a rule of thumb I use pessimistic locking when the chances of a collision are high (or transactions are short lived) and optimistic locking when the chances of a collision are low (or transactions are long lived, or your business rules encompass multiple transactions).

You really need to see what applies to your situation and make a judgment call.

Glen
Also I would never put pessimistic locks where it waits on user edits.
DJ
@DJ good point, I forgot to mention that.
Glen
@Glen said "one thing to watch out for here is if 2 updates occur within the resolution of the Date column your logic will fail. It's a pretty rare edge case, but it can still occur." However, one will get the lock (remember it is in a transaction), the other one will not and it will wait and then the dates will be different when it gets it chance to update.
KM
+1  A: 

here's a simple solution to many people working on the same records.

when you load the data, get the last changed date, we use LastChgDate on our tables

when you save (update) the data add "AND LastChgDate=previouslyLoadedLastChgDate" to the where clause. If the row count=0 on the update, issue error where "someone else has already saved this data" and rollback everything, otherwise the data is saved.

I generally do the above logic on header tables only and not on the details tables, since they are all in one transaction.

KM
one thing to watch out for here is if 2 updates occur within the resolution of the Date column your logic will fail. It's a pretty rare edge case, but it can still occur.
Glen
@Glen, one will get the lock (remember it is in a transaction), the other one will not and it will wait and then the dates will be different when it gets it chance to update.
KM
+3  A: 

Optimistic locking.
Pessimistic is harder to implement and will give problems in a web environment. What action will release the lock, closing the browser? Leaving the session to time out? What about if they then do save their changes?

You don't specify which database you are using. MS SQL server has a timestamp datatype. It has nothing to do with time though. It is mearly a number that will get changed each time the row gets updated. You don't have to do anything to make sure it gets changed, you just need to check it. You can achive similar by using a date/time last modified as @KM suggests. But this means you have to remember to change it each time you update the row. If you use datetime you need to use a data type with sufficient precision to ensure that you can't end up with the value not changing when it should. For example, some one saves a row, then someone reads it, then another save happens but leaves the modified date/time unchanged. I would use timestamp unless there was a requirement to track last modified date on records.

To check it you can do as @KM suggests and include it in the update statement where clause. Or you can begin a transaction, check the timestamp, if all is well do the update, then commit the transaction, if not then return a failure code or error.

Holding transactions open (as suggested by @le dorfier) is similar to pessimistic locking, but the amount of data locked may be more than a row. Most RDBM's lock at the page level by default. You will also run into the same issues as with pessimistic locking.

You mention in your question that you are worried about conflicting updates. That is what the locking will prevent surely. Both optimistic or pessimistic will, when properly implemented prevent exactly that.

pipTheGeek
I like the last change date better than the timestamp data type, because it contains useful data. We also have a LastChgID to track the person, both these columns are nice to display, where a timestamp data type column is meaningless to display.
KM
If this sort of data is already a requirement then there is no reason not to use it. I have updated my answer accordingly.
pipTheGeek
+2  A: 

I agree with the first answer above, we try to use optimistic locking when the chance of collisions is fairly low. This can be easily implemented with a LastModifiedDate column or incrementing a Version column. If you are unsure about frequency of collisions, log occurrences somewhere so you can keep an eye on them. If your records are always in "edit" mode, having separate "view" and "edit" modes could help reduce collisions (assuming you reload data when entering edit mode).

If collisions are still high, pessimistic locking is more difficult to implement in web apps, but definitely possible. We have had good success with "leasing" records (locking with a timeout)... similar to that 2 minute warning you get when you buy tickets on TicketMaster. When a user goes into edit mode, we put a record into the "lock" table with a timeout of N minutes. Other users will see a message if they try to edit a record with an active lock. You could also implement a keep-alive for long forms by renewing the lease on any postback of the page, or even with an ajax timer. There is also no reason why you couldn't back this up with a standard optimistic lock mentioned above.

Many apps will need a combination of both approaches.

chaiwalla