Overvej følgende skema:(Rem stmts tilbage for din bekvemmelighed) :
-- 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 og P2. Bedst at teste, hvor P1 måske er MySQL Workbench og P2 er et MySql kommandolinjevindue. Med andre ord skal du sætte dette op som separate forbindelser og højre. Du skal have et omhyggeligt øje for trin-for-trin at køre disse på den rigtige måde (beskrevet i Fortællingen nedenfor) og se dets indvirkning på det andet procesvindue.
Overvej følgende forespørgsler, og husk, at en mysql-forespørgsel, der ikke er pakket ind i en eksplicit transaktion, i sig selv er en implicit transaktion. Men nedenfor svang jeg efter eksplicit:
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;
Q4:
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;
Fortælling
Q1: Når P1 begynder at begynde Q1 , og når til place2, har den opnået en eksklusiv opdateringslås på rækkeniveau i både bordvåben og spioner for id=1 rækken (total rækker, 1 række i hver tabel). Dette kan bevises ved, at P2 begynder at køre Q3, kommer til place1, men blokerer på plads2, og først bliver frigivet, når P1 kommer til at kalde COMMIT. Alt, hvad jeg lige har sagt om P2, der kører Q3, er ditto for P2, der kører Q4. Sammenfattende, på P2-skærmen fryser sted2, indtil P1 Commit.
En bemærkning igen om implicitte transaktioner. Din rigtige Q1-forespørgsel kommer til at udføre dette meget hurtigt, og at komme ud af det vil gøre en implicit commit. Men det foregående afsnit opdeler det, hvis du skulle have mere tidskrævende rutiner kørende.
Q2: Når P1 begynder at begynde Q2 , og når til place2, har den opnået en eksklusiv opdateringslås på rækkeniveau i både bordvåben og spioner for id=1 rækken (total rækker, 1 række i hver tabel). P2 har dog ingen problemer med Q3-blokering af weapons
, men P2 har blokproblemer, der kører Q4 hos place2 spies
.
Så forskellene mellem Q1 og Q2 kommer ned til, at MySQL ved, at FK-indekset ikke er relevant for en kolonne i OPDATERING, og manualen siger, at i Note1 nedenfor.
Når P1 kører Q1, har P2 ingen problemer med den skrivebeskyttede ikke-låse, der indhenter Q5-typer af forespørgsler. De eneste problemer er, hvilke datagengivelser P2 ser baseret på det eksisterende ISOLATIONSNIVEAU.
Bemærkning 1 :Fra MySQL-manualsiden med titlen Låse indstillet af forskellige SQL-sætninger i InnoDB :
Ovenstående er grunden til, at Q2:s adfærd er sådan, at P2 frit kan udføre en OPDATERING eller erhverve en UPDATE eksklusiv momentan lås på weapons
. Dette skyldes, at motoren ikke udfører en OPDATERING med P1 på weapon_id og derfor ikke har en række-niveau-lås i den tabel.
For at trække dette tilbage til 50.000 fod er ens største bekymring varigheden, hvor en lås holdes enten i en implicit transaktion (en uden START/COMMIT) eller eksplicit transaktion før en COMMIT. En peer-proces kan i teorien forbydes at erhverve sit behov for en OPDATERING på ubestemt tid. Men hvert forsøg på at erhverve den lås er styret af dens indstilling for innodb_lock_wait_timeout . Hvad det betyder er, at det som standard efter ca. 60 sekunder timeout. For at se din indstilling skal du køre:
select @@innodb_lock_wait_timeout;
For mig er det i øjeblikket 50 (sekunder).