Hello.
> BEGIN;
> SELECT id FROM ttt WHERE id=3D7 FOR UPDATE;
> INSERT INTO ttt(id) VALUES (7);
> DELETE FROM ttt WHERE id=3D7;
> COMMIT;
Maybe we have this scenario:
A, B - transactions.
A -> SELECT ... FOR UPDATE - is setting an X lock on index for id=8
(next key locking, it is preventing the insertion of record with id=8)
B -> INSERT ... - is trying to get a lock and waits for A to release a
lock
A-> INSERT ... - A already has a lock (which is wasn't released by an
UPDATE statement). A is trying to get another one,
but B is already in the queue
In my opinion, UPDATE statement should be run immediately after
SELECT ... FOR UPDATE. BTW, your situation is a beat easier to
reproduce with this perl script (I put it here in case somebody has a
better scenario):
[EMAIL PROTECTED] pl]$ cat deadlock.pl
#!/usr/bin/perl
use strict;
use DBI;
my ($dbh,$sql,$dsn);
$dsn =
"DBI:mysql:database=test;host=localhost;mysql_socket=/home/gleb/mysqls/tmp/mysql.sock.gleb.d";
$dbh = DBI->connect
($dsn,
"root","",
{RaiseError => 1})
or die "connecting : $DBI::errstr\n";
$sql = "create table if not exists ttt(
id int unsigned not null
auto_increment primary key)";
$dbh->do($sql);
$sql = "begin";
$dbh->do($sql);
$sql = "select id from ttt where id=7 for update";
$dbh->do($sql);
sleep(1);
$sql = "insert into ttt set id=7";
$dbh->do($sql);
sleep(1);
$sql = "delete from ttt where id=7";
$dbh->do($sql);
$sql = "commit";
$dbh->do($sql);
$dbh->disconnect;
Run it as
for i in 1 2 3 4 5 6 7 8 9; do ./deadlock.pl & done
The snip from the output of 'SHOW INNODB STATUS':
------------------------
051007 23:09:51
*** (1) TRANSACTION:
TRANSACTION 0 1976, ACTIVE 1 sec, process no 2119, OS thread id 2768907
insertin
g
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 320
MySQL thread id 160, query id 848 localhost root update
insert into ttt set id=7
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 9 page no 3 n bits 72 index `PRIMARY` of table
`test/ttt`
trx id 0 1976 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info
bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
*** (2) TRANSACTION:
TRANSACTION 0 1984, ACTIVE 1 sec, process no 2132, OS thread id 2899987
insertin
g
mysql tables in use 1, locked 1
3 lock struct(s), heap size 320
MySQL thread id 168, query id 863 localhost root update
insert into ttt set id=7
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 9 page no 3 n bits 72 index `PRIMARY` of table
`test/ttt`
trx id 0 1984 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info
bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 9 page no 3 n bits 72 index `PRIMARY` of table
`test/ttt`
trx id 0 1984 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info
bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
Pooly wrote:
> Hi,
>
> I had that error for quiet a long time, and I usually restart the
> transaction, but sometimes I have to do it 2 or 3 times, and I don't
> really understand how it can happen.
> I've strip down an example, that does basically :
>
> BEGIN;
> SELECT id FROM ttt WHERE id=3D7 FOR UPDATE;
> INSERT INTO ttt(id) VALUES (7);
> DELETE FROM ttt WHERE id=3D7;
> COMMIT;
>
> I run 10 instances of the program in parallel and I get the error :
> Deadlock found when trying to get lock; try restarting transaction.
> The isolation level is the default one.
> My understanding of the SELECT ... FOR UPDATE is that I should not get
> that deadlock, all transaction should be waiting on this select. From
> the manual :
> A SELECT ... FOR UPDATE reads the latest available data, setting
> exclusive locks on each row it reads.
> All instances should select the latest data, or wait until the lock is rele=
> ased.
> Does anyone have pointer for a better explanations ?
>
> Here is my program which I run in parallel with :
> for i in 1 2 3 4 5 6 7 8 9; do ./test_mysql $i & done
>
>
> #include "mysql/mysql.h"
> #include <stdio.h>
>
> int main(int argc, char **argv)
> {
> MYSQL *mysql;
> int insert =3D0;
>
> my_init();
>
> mysql =3D mysql_init((MYSQL*)NULL);
> if(! mysql_real_connect( mysql,
> "127.0.0.1",
> "root",
> "",
> "test",
> 3306,
> NULL,
> CLIENT_COMPRESS) ) {
> printf("Connexion failed.\n");
> mysql_close(mysql);
> } else {
> int ret;
> printf("%s : create table\n", argv[1]);
> ret =3D mysql_query(mysql,
> "CREATE TABLE IF NOT EXISTS ttt "
> "( id integer unsigned NOT NULL AUTO_INCREM=
> ENT,"
> "PRIMARY KEY(id) "
> ") Engine=3DInnoDB;");
> if ( ret ) {
> printf("%s : Creation failed %s\n", argv[1],
> mysql_error(mysql));
> return 1;
> }
> printf("%s : Begin\n", argv[1]);
> ret =3D mysql_query(mysql, "BEGIN");
> if (ret) {
> printf("%s : Begin failed %s\n", argv[1],
> mysql_error(mysql));
> return 1;
> }
> printf("%s : Begin ok\n", argv[1]);
> printf("%s : Select for update\n", argv[1]);
> ret =3D mysql_query(mysql,
> "SELECT id FROM ttt WHERE id=3D7 FOR UPDATE=
> ");
> if ( ret ) {
> printf("%s : select failed : %s\n", argv[1],
> mysql_error(mysql));
> return 1;
> } else {
> MYSQL_RES *res;
> res =3D mysql_store_result(mysql);
> if ( res && mysql_num_rows(res) ) {
> printf("%s : found a row\n", argv[1]);
> insert =3D 0;
> } else {
> printf("%s : found no row\n", argv[1]);
> insert =3D 1;
> }
> if ( res )
> mysql_free_result(res);
> }
> printf("%s : Select for udate OK\n", argv[1]);
> printf("%s : sleep\n");
> sleep(1);
> /* should be ok to check and not fire a timeout */
> if (insert ) {
> printf("%s : insertion \n", argv[1]);
> ret =3D mysql_query(mysql,
> "INSERT INTO ttt(id) VALUES (7)");
> if ( ret ) {
> printf("%s : insert failed : %s\n",
> argv[1], mysql_error(mysql));
> return 1;
> }
> printf("%s : delete it \n", argv[1]);
> ret =3D mysql_query(mysql,
> "DELETE FROM ttt WHERE id=3D7");
> if ( ret ) {
> printf("%s : delete failed : %s\n",
> argv[1], mysql_error(mysql));
> return 1;
> }
> }
> printf("%s : commit\n", argv[1]);
> ret =3D mysql_query(mysql, "COMMIT");
> if ( ret ) {
> printf("%s : commit failed : %s\n", argv[1],
> mysql_error(mysql));
> return 1;
> }
> printf("%s : Commit ok\n", argv[1]);
>
> }
> return 0;
> }
>
>
>
> --
> Pooly
> Webzine Rock : http://www.w-fenec.org/
>
--
For technical support contracts, goto https://order.mysql.com/?ref=ensita
This email is sponsored by Ensita.NET http://www.ensita.net/
__ ___ ___ ____ __
/ |/ /_ __/ __/ __ \/ / Gleb Paharenko
/ /|_/ / // /\ \/ /_/ / /__ [EMAIL PROTECTED]
/_/ /_/\_, /___/\___\_\___/ MySQL AB / Ensita.NET
<___/ www.mysql.com
--
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe: http://lists.mysql.com/[EMAIL PROTECTED]