NYCPHP Meetup

NYPHP.org

[nycphp-talk] mysql concurrency redux

David Mintz dmintz at davidmintz.org
Tue Feb 24 11:43:48 EST 2004


Still having trouble understanding how to avoid the Lost Update Problem,
which was discussed here a couple months ago
(http://lists.nyphp.org/pipermail/talk/2003-December/006718.html etc).

An HTML form is populated with data from a db, including a field holding
my last_modified timestamp so I can compare it with the db before I write
the update.

How is using a transaction supposed to prevent another client from
sneaking in an update after I compare, but before I write?

I've read that you should either lock tables or use transactions. My
experiment (below) seems to suggest transactions alone is not enough and I
have to lock tables as well, or instead. But that doesn't sound right -- I
must be confused.

I've tried setting the isolation level to "read uncommitted" and it makes
no difference.

Here's the table.

CREATE TABLE test01 (
  id smallint(6) NOT NULL auto_increment,
  string varchar(75) default NULL,
  lastmod timestamp(14) NOT NULL,
  PRIMARY KEY  (id)
) TYPE=InnoDB;


INSERT INTO test01 VALUES (1,'bla bla bla', NOW());
--

Here's the experiment. When I load a copy into each of two windows and
submit both so they overlap in time, I expect the first to succeed and the
second to abort. Is there something stupid I'm doing wrong here? (btw I am
making sure to submit something in the 'string' field that's different
from what's in the db to ensure that my timestamp updates)

<?php

require('DB.php');
$db=DB::connect('mysql://joe_user@localhost/test');
$db->setFetchMode(DB_FETCHMODE_ASSOC);

if($_SERVER['REQUEST_METHOD']=='POST') {

        $db->query("set transaction isolation level READ UNCOMMITTED");
        $db->query("start transaction");
        // compare our timestamp with db
        $theirs = $db->getOne("select lastmod from test01 where id=1");
        echo "sleeping..."; flush();
        sleep(4);
        if ($theirs != $_POST['lastmod']) {
                echo "record has been modified by someone else.
reloading...";
                $db->query("rollback");
        } else {
                $db->query('update test01 set string ='  .
$db->quote($_POST['string']) . ' where id=1');
                $db->query("commit");
                echo "ok, $theirs = {$_POST['lastmod']}, updating... ";
        }
}
$formData = $db->getRow("select * from test01 where id = 1");
?>

<form action="<?=$_SERVER['PHP_SELF']?>" method="POST">
        Id <input type="text" size="2" name="id"
value="<?=$formData['id']?>" /><br />
        Last Mod <input type="text" size="24" name="lastmod"
value="<?=$formData['lastmod']?>" /><br />
        String <input type="text" size="30" name="string"
value="<?=htmlspecialchars($formData['string'])?>" /><br />
        <input type="submit" />
</form>

FWIW I've tried this with both 4.0.13-standard and 4.0.16-max-nt-log, both
with PEAR DB 1.6.0RC6


Many many thanks,


---
David Mintz
http://davidmintz.org/

        "Anybody else got a problem with Webistics?" -- Sopranos 24:17



More information about the talk mailing list