Tänk på följande schema:(Rem stmts lämnade för din bekvämlighet) :
-- drop table if exists spies;
create table spies
( id int primary key,
weapon_id int not null,
name varchar(100) not null,
key(weapon_id),
foreign key (weapon_id) references weapons(id)
)engine=InnoDB;
-- drop table if exists weapons;
create table weapons
( id int primary key,
name varchar(100) not null
)engine=InnoDB;
insert weapons(id,name) values (1,'slingshot'),(2,'Ruger');
insert spies(id,weapon_id,name) values (1,2,'Sally');
-- truncate table spies;
Nu har vi 2 processer, P1 och P2. Bäst att testa var P1 kanske är MySQL Workbench och P2 är ett MySql kommandoradsfönster. Med andra ord måste du ställa in detta som separata anslutningar och rätt. Du måste ha ett noggrant öga för att steg-för-steg köra dessa på rätt sätt (beskrivs i Berättelsen nedan) och se dess inverkan på det andra processfönstret.
Tänk på följande frågor och tänk på att en mysql-fråga som inte är insvept i en explicit transaktion i sig är en implicit transaktion. Men nedan svängde jag för explicit:
Q1:
START TRANSACTION;
-- place1
UPDATE spies SET name = 'Bond', weapon_id = 1 WHERE id = 1;
-- place2
COMMIT;
Q2:
START TRANSACTION;
-- place1
UPDATE spies SET name = 'Bond' WHERE id = 1;
-- place2
COMMIT;
Q3:
START TRANSACTION;
-- place1
SELECT id into @mine_to_use from weapons where id=1 FOR UPDATE; -- place2
-- place3
COMMIT;
F4:
START TRANSACTION;
-- place1
SELECT id into @mine_to_use from spies where id=1 FOR UPDATE; -- place2
-- place3
COMMIT;
Q5 (hodge podge of queries):
SELECT * from weapons;
SELECT * from spies;
Berättelse
Q1: När P1 börjar börja Q1 , och kommer till plats2, har den fått ett exklusivt uppdateringslås på radnivå i både bordsvapen och spioner för raden id=1 (totalt 2 rader, 1 rad i varje tabell). Detta kan bevisas genom att P2 börjar köra Q3, kommer till plats1, men blockerar på plats2, och först frigörs när P1 kommer runt för att syna COMMIT. Allt jag just sa om att P2 kör Q3 är dito för P2 som kör Q4. Sammanfattningsvis, på P2-skärmen fryser plats2 tills P1 Commit.
En anteckning igen om implicita transaktioner. Din riktiga Q1-frågan kommer att utföra detta mycket snabbt och kommer ut ur det kommer att göra en implicit commit. Men det föregående stycket bryter ner det om du skulle ha mer tidkostsamma rutiner igång.
Fråga 2: När P1 börjar börja Q2 , och kommer till plats2, har den fått ett exklusivt uppdateringslås på radnivå i både bordsvapen och spioner för raden id=1 (totalt 2 rader, 1 rad i varje tabell). P2 har dock inga problem med Q3-blockering av weapons
, men P2 har blockeringsproblem som kör Q4 på place2 spies
.
Så, skillnaderna mellan Q1 och Q2 beror på att MySQL vet att FK-indexet inte är relevant för en kolumn i UPPDATERING, och manualen säger att i Note1 nedan.
När P1 kör Q1, har P2 inga problem med den skrivskyddade icke-låsta som hämtar Q5-typer av frågor. De enda problemen är vilka dataåtergivningar P2 ser baserat på den befintliga ISOLATIONSNIVÅN.
Anmärkning 1 :Från MySQL-manualsidan med titeln Lås Set by Different SQL-satser i InnoDB :
Ovanstående är anledningen till beteendet hos Q2: är sådan att P2 är fri att utföra en UPPDATERING eller skaffa ett exklusivt UPPDATERING tillfälligt lås på weapons
. Detta beror på att motorn inte utför en UPPDATERING med P1 på weapon_id och därför inte har något radnivålås i den tabellen.
För att dra tillbaka detta till 50 000 fot, är ens största oro hur länge ett lås hålls antingen i en implicit transaktion (en utan START/COMMIT), eller explicit transaktion före en COMMIT. En peer-process kan förbjudas att förvärva sitt behov av en UPPDATERING i teorin på obestämd tid. Men varje försök att skaffa det låset styrs av dess inställning för innodb_lock_wait_timeout . Vad det betyder är, som standard, efter cirka 60 sekunder. Kör:
för att se din inställningselect @@innodb_lock_wait_timeout;
För mig är det för tillfället 50 (sekunder).