Question

A team member has run into an issue with an old in-house system where a user double-clicking on a link on a web page can cause two requests to be sent from the browser resulting in two database inserts of the same record in a race condition; the last one to run fails with a primary key violation. Several solutions and hacks have been proposed and discussed:

  1. Use Javascript on the web page to mitigate the second click by disabling the link on the first click. This is a quick and easy way to reduce the occurrences of the problem, but not entirely eliminate it.

  2. Wrap the request execution on the sever side in a transaction. This has been deemed too expensive of an operation due to server load and lock levels on the table in question.

  3. Catch the primary key exception thrown by the failed insert, identify it as such, and eat it. This has the disadvantages of (a) vendor lock-in, having to know the nuances of the database-specific exceptions, and (b) potentially not logging/dealing with legitimate database failures.

  4. An extension of #3 by attempting to update the record if the insert fails and checking the result of the update to ensure it returns 1 record affected.

Are the other options that haven't been considered? Are there pros and cons of the options presented that were overlooked? Which is the lesser of all evils?

Was it helpful?

Solution

You need to implement the Synchronizer Token pattern.

How it works is: a value (the token) is generated on the server for each request. This same token must then be included in your form submission. On receipt of the request the server token and client token are compared and if they are the same you may continue to add your record. The server side token is then regenerated, so subsequent requests containing the old token will fail.

There's a more thorough explanation about half-way down this page.

I'm not sure what technology you're using, but Struts provides framework level support for this pattern. See example here

OTHER TIPS

Put a unique identifier on the page in a hidden field. Only accept one response with a given unique identifier.

It sounds like you might be misusing a GET request to modify server state (although this is not necessarily the case). While it may not be appropriate for you situation, it should be stated that you should consider converting the link into a form POST.

It seems you already replied to your own question there; #1 seems to be the only viable option.

Otherwise, you should really do all three steps -- data integrity should be handled at the database level, but extra checks (such as the explicit transaction) in the code to avoid roundtrips to the database could be good for performance.

REF You need to implement the Synchronizer Token pattern.

This is for Javascript/HTML not JAVA

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top