<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: Resolving transaction concurrency issues in a PHP+MySQL multi-user environment</title>
	<atom:link href="http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/</link>
	<description>Ardamis is a blog about web development and technology in general.</description>
	<lastBuildDate>Fri, 03 Feb 2012 03:06:09 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
	<item>
		<title>By: Paul Schmidt</title>
		<link>http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-69974</link>
		<dc:creator>Paul Schmidt</dc:creator>
		<pubDate>Fri, 09 Dec 2011 13:06:08 +0000</pubDate>
		<guid isPermaLink="false">http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-69974</guid>
		<description>Correction on the sequence of events above.  Record &quot;A&quot; would have had to be inserted or updated in that second, also.  Note that the last save by User B does not have to happen in that second.</description>
		<content:encoded><![CDATA[<p>Correction on the sequence of events above.  Record &#8220;A&#8221; would have had to be inserted or updated in that second, also.  Note that the last save by User B does not have to happen in that second.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Paul Schmidt</title>
		<link>http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-69833</link>
		<dc:creator>Paul Schmidt</dc:creator>
		<pubDate>Thu, 08 Dec 2011 21:02:21 +0000</pubDate>
		<guid isPermaLink="false">http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-69833</guid>
		<description>Great article.  The problem of multiple applications colliding in this environment is usually small and a locking mechanism is overkill.  The idea of using the timestamp is a really elegant and simple solution.  Of course, use it the way Tony and Jason have described to reduce the chances of errors.  Note that this does not totally eliminate problems but significantly reduces the chance. An example of where an error would still occur:

User A opens record “A”.
User B opens record “A”.
User A saves changes to record “A”.
User B saves changes to record “A”.

all takes place in the same second.

For most applications this is a very unlikely event.  Another option would be to add a version number.  This number would need to be incremented on every update and put into the where clause.  This would guarantee that the record was only updated once.  Note that Transact-SQL (aka mssql) uses this approach with a global number that is referred to as either timestamp or rowversion.

One of the best things about this implementation is that it can be used when needed and added to already designed and coded websites when used with a timestamp.  Any updates will modify the timestamp and no extra code needs to be written.  The timestamp column can be added later.  So, if one is worried about data integrity for a certain highly used web page, it can be added to that page with no bad side effects.  

You can also, if desired, make the system more robust by adding a merge function that would look to see what had been changed and how to merge the two changes together.  To implement this, though, you would need an original copy of the record, the updated record you are trying to write, and the current record in the database.  So merge functionality would only be worth implementing for updates with high collisions.</description>
		<content:encoded><![CDATA[<p>Great article.  The problem of multiple applications colliding in this environment is usually small and a locking mechanism is overkill.  The idea of using the timestamp is a really elegant and simple solution.  Of course, use it the way Tony and Jason have described to reduce the chances of errors.  Note that this does not totally eliminate problems but significantly reduces the chance. An example of where an error would still occur:</p>
<p>User A opens record “A”.<br />
User B opens record “A”.<br />
User A saves changes to record “A”.<br />
User B saves changes to record “A”.</p>
<p>all takes place in the same second.</p>
<p>For most applications this is a very unlikely event.  Another option would be to add a version number.  This number would need to be incremented on every update and put into the where clause.  This would guarantee that the record was only updated once.  Note that Transact-SQL (aka mssql) uses this approach with a global number that is referred to as either timestamp or rowversion.</p>
<p>One of the best things about this implementation is that it can be used when needed and added to already designed and coded websites when used with a timestamp.  Any updates will modify the timestamp and no extra code needs to be written.  The timestamp column can be added later.  So, if one is worried about data integrity for a certain highly used web page, it can be added to that page with no bad side effects.  </p>
<p>You can also, if desired, make the system more robust by adding a merge function that would look to see what had been changed and how to merge the two changes together.  To implement this, though, you would need an original copy of the record, the updated record you are trying to write, and the current record in the database.  So merge functionality would only be worth implementing for updates with high collisions.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Jason</title>
		<link>http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-64898</link>
		<dc:creator>Jason</dc:creator>
		<pubDate>Thu, 27 Oct 2011 17:05:20 +0000</pubDate>
		<guid isPermaLink="false">http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-64898</guid>
		<description>**Important - Read Tony&#039;s comment above!**

The server can switch between users A and B at any time, and there is a problem with the &#039;straightforward&#039; sequence described at the top depending on how you implement it (read-modify-write sequence). Going back to the description of the solution, there is a fatal flaw if the following sequence of events happens when the two users try to write the same record (almost) simultaneously:

At 10:30 AM, User A attempts to save the record. The “last-saved timestamp” is retrieved from the record. -- Server BREAKS HERE and switches attention to User B --

At 10:30 AM, User B attempts to save the record. The “last-saved timestamp” is retrieved from the record. The “opened timestamp” of 10:00 AM is compared to the “last-saved timestamp” of 9:00 AM. Because the record has not been changed since it was opened, the record is saved. A new “last-saved timestamp” of 10:30 AM is generated and saved to the record.

-- Server BREAKS HERE and returns to User A --

The “opened timestamp” of 10:00 AM is compared to the “last-saved timestamp” of 9:00 AM (oops - now it&#039;s the wrong value, but this was the value read above at the start...). Because the record has not been changed since it was opened, the record is saved (again). A new “last-saved timestamp” of 10:30 AM is generated and saved to the record.

The problem has not been solved because the &#039;read&#039; of the new timestamp followed by the check on it followed by the &#039;write&#039; of the new timestamp can be interrupted. If one &#039;read&#039; interrupts another then both reads end up with the same, old, value, and both threads will &#039;write&#039; their new record.

Solution? See Tony&#039;s comment - this is IMPORTANT! The operation to read, check and write the timestamp (for both A and B) must be one indivisible transaction, i.e. use:

[sourcecode]UPDATE row WHERE “opened timestamp” = “last modified timestamp”[/sourcecode]

You need to check the result of this operation (how many rows were affected...?) to handle the case where someone else has updated it. In this case your update did not work...</description>
		<content:encoded><![CDATA[<p>**Important &#8211; Read Tony&#8217;s comment above!**</p>
<p>The server can switch between users A and B at any time, and there is a problem with the &#8216;straightforward&#8217; sequence described at the top depending on how you implement it (read-modify-write sequence). Going back to the description of the solution, there is a fatal flaw if the following sequence of events happens when the two users try to write the same record (almost) simultaneously:</p>
<p>At 10:30 AM, User A attempts to save the record. The “last-saved timestamp” is retrieved from the record. &#8212; Server BREAKS HERE and switches attention to User B &#8211;</p>
<p>At 10:30 AM, User B attempts to save the record. The “last-saved timestamp” is retrieved from the record. The “opened timestamp” of 10:00 AM is compared to the “last-saved timestamp” of 9:00 AM. Because the record has not been changed since it was opened, the record is saved. A new “last-saved timestamp” of 10:30 AM is generated and saved to the record.</p>
<p>&#8211; Server BREAKS HERE and returns to User A &#8211;</p>
<p>The “opened timestamp” of 10:00 AM is compared to the “last-saved timestamp” of 9:00 AM (oops &#8211; now it&#8217;s the wrong value, but this was the value read above at the start&#8230;). Because the record has not been changed since it was opened, the record is saved (again). A new “last-saved timestamp” of 10:30 AM is generated and saved to the record.</p>
<p>The problem has not been solved because the &#8216;read&#8217; of the new timestamp followed by the check on it followed by the &#8216;write&#8217; of the new timestamp can be interrupted. If one &#8216;read&#8217; interrupts another then both reads end up with the same, old, value, and both threads will &#8216;write&#8217; their new record.</p>
<p>Solution? See Tony&#8217;s comment &#8211; this is IMPORTANT! The operation to read, check and write the timestamp (for both A and B) must be one indivisible transaction, i.e. use:</p>
<pre class="brush: plain; title: ; notranslate">UPDATE row WHERE “opened timestamp” = “last modified timestamp”</pre>
<p>You need to check the result of this operation (how many rows were affected&#8230;?) to handle the case where someone else has updated it. In this case your update did not work&#8230;</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: ardamis</title>
		<link>http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-41955</link>
		<dc:creator>ardamis</dc:creator>
		<pubDate>Sat, 31 Jul 2010 02:50:49 +0000</pubDate>
		<guid isPermaLink="false">http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-41955</guid>
		<description>I would think that if only one user can access any given record, then there would be less opportunity for problems to arise.  But there is still a possibility that data could be lost.  For example, a user could access the same record from two separate browsers (log in from home, leave that page up, and then log in later from work) and cause data loss in the same way as two different users accessing a single record.

In my opinion, a responsible developer will work to eliminate any possibility of data loss, however unlikely.</description>
		<content:encoded><![CDATA[<p>I would think that if only one user can access any given record, then there would be less opportunity for problems to arise.  But there is still a possibility that data could be lost.  For example, a user could access the same record from two separate browsers (log in from home, leave that page up, and then log in later from work) and cause data loss in the same way as two different users accessing a single record.</p>
<p>In my opinion, a responsible developer will work to eliminate any possibility of data loss, however unlikely.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: David DelMonte</title>
		<link>http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-41952</link>
		<dc:creator>David DelMonte</dc:creator>
		<pubDate>Sat, 31 Jul 2010 02:00:58 +0000</pubDate>
		<guid isPermaLink="false">http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-41952</guid>
		<description>Would you all recommend the same solution if every user&#039;s data was their own. I am building an app which people can use off of my site, but they each have their own data. Do I replicate the database or follow the examples here, or do something different.. I would appreciate your wisdom..</description>
		<content:encoded><![CDATA[<p>Would you all recommend the same solution if every user&#8217;s data was their own. I am building an app which people can use off of my site, but they each have their own data. Do I replicate the database or follow the examples here, or do something different.. I would appreciate your wisdom..</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Jon di Elos</title>
		<link>http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-31811</link>
		<dc:creator>Jon di Elos</dc:creator>
		<pubDate>Tue, 20 Apr 2010 19:02:52 +0000</pubDate>
		<guid isPermaLink="false">http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-31811</guid>
		<description>Why not relly on MySQL innoDB concurrency model? Is there any problem requirement which makes innodb inpractical in this case? Did I miss something?

Regards,
Jon di Leos</description>
		<content:encoded><![CDATA[<p>Why not relly on MySQL innoDB concurrency model? Is there any problem requirement which makes innodb inpractical in this case? Did I miss something?</p>
<p>Regards,<br />
Jon di Leos</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: ardamis</title>
		<link>http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-18173</link>
		<dc:creator>ardamis</dc:creator>
		<pubDate>Mon, 01 Jun 2009 20:09:46 +0000</pubDate>
		<guid isPermaLink="false">http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-18173</guid>
		<description>A hash is a great idea, and in one implementation, it could eliminate the need for each record to contain the timestamp data.  However, as pointed out in another comment, attempting to modify the record using an UPDATE that looks for the timestamp serves to check that the record can be modified at the same instant it would be changed.

I&#039;m not at all familiar with the risks involved with thread switching, but it seems to me that there still exists the potential for data loss in the time it takes the server to calculate the MD5 sum and then send the data to the database.

I&#039;ll certainly consider using it the next time this issue comes up, though.</description>
		<content:encoded><![CDATA[<p>A hash is a great idea, and in one implementation, it could eliminate the need for each record to contain the timestamp data.  However, as pointed out in another comment, attempting to modify the record using an UPDATE that looks for the timestamp serves to check that the record can be modified at the same instant it would be changed.</p>
<p>I&#8217;m not at all familiar with the risks involved with thread switching, but it seems to me that there still exists the potential for data loss in the time it takes the server to calculate the MD5 sum and then send the data to the database.</p>
<p>I&#8217;ll certainly consider using it the next time this issue comes up, though.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Steve</title>
		<link>http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-18172</link>
		<dc:creator>Steve</dc:creator>
		<pubDate>Mon, 01 Jun 2009 19:27:07 +0000</pubDate>
		<guid isPermaLink="false">http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-18172</guid>
		<description>I prefer to use a hash of the original record. When user A retrieves the record for editing, I generate an MD5 hash of the record data that is included as a hidden field in the form. When the user tries to write the record, I can determine whether the record was changed by comparing the MD5 hash. That eliminates the need to manage the timestamps.</description>
		<content:encoded><![CDATA[<p>I prefer to use a hash of the original record. When user A retrieves the record for editing, I generate an MD5 hash of the record data that is included as a hidden field in the form. When the user tries to write the record, I can determine whether the record was changed by comparing the MD5 hash. That eliminates the need to manage the timestamps.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Tom Christopherson</title>
		<link>http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-18153</link>
		<dc:creator>Tom Christopherson</dc:creator>
		<pubDate>Fri, 29 May 2009 22:57:36 +0000</pubDate>
		<guid isPermaLink="false">http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-18153</guid>
		<description>Thanks for the write up... i&#039;ve been wrestling with the same design issue for some time now and your explaination is the best I&#039;ve seen yet as a possible solution.</description>
		<content:encoded><![CDATA[<p>Thanks for the write up&#8230; i&#8217;ve been wrestling with the same design issue for some time now and your explaination is the best I&#8217;ve seen yet as a possible solution.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Tony</title>
		<link>http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-16949</link>
		<dc:creator>Tony</dc:creator>
		<pubDate>Fri, 26 Sep 2008 11:41:16 +0000</pubDate>
		<guid isPermaLink="false">http://www.ardamis.com/2008/04/06/resolving-transaction-concurrency-issues-in-a-phpmysql-multi-user-environment/#comment-16949</guid>
		<description>Pretty cool solution. To add to that, it works great when process collision is greater than the granularity of the MySql timestamp which is per second. ie, no 2 process will do a read/write within 1 second.

To get around this, you can store the time as a bigint which can handle milliseconds. Unless you have some serious hardware, I don&#039;t think collision granularity would go smaller than milliseconds.

Also instead of re-reading the timestamp before B saves, B should try to UPDATE row WHERE &quot;opened timestamp&quot; = &quot;last modified timestamp&quot;. Otherwise the CPU could potentially decide to switch threads on you right after you&#039;ve done the second read, and do the entire read-write of A in that time.</description>
		<content:encoded><![CDATA[<p>Pretty cool solution. To add to that, it works great when process collision is greater than the granularity of the MySql timestamp which is per second. ie, no 2 process will do a read/write within 1 second.</p>
<p>To get around this, you can store the time as a bigint which can handle milliseconds. Unless you have some serious hardware, I don&#8217;t think collision granularity would go smaller than milliseconds.</p>
<p>Also instead of re-reading the timestamp before B saves, B should try to UPDATE row WHERE &#8220;opened timestamp&#8221; = &#8220;last modified timestamp&#8221;. Otherwise the CPU could potentially decide to switch threads on you right after you&#8217;ve done the second read, and do the entire read-write of A in that time.</p>
]]></content:encoded>
	</item>
</channel>
</rss>

