Zvažte následující schéma:(Ponechané položky pro vaše pohodlí) :
-- 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;
Nyní máme 2 procesy, P1 a P2. Nejlepší je vyzkoušet, kde P1 je možná MySQL Workbench a P2 je okno příkazového řádku MySql. Jinými slovy, musíte to nastavit jako samostatná připojení a správně. Museli byste mít pečlivé oko, abyste je krok za krokem provedli správným způsobem (popsáno v Příběhu níže) a podívejte se na jeho dopad na další okno procesu.
Zvažte následující dotazy a mějte na paměti, že dotaz mysql, který není zabalen do explicitní transakce, je sám o sobě implicitní transakcí. Ale níže jsem se obrátil na explicitní:
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 dotazů):
SELECT * from weapons;
SELECT * from spies;
Příběh
O1: Když P1 začne začínat Q1 a dostane se na místo2, získal exkluzivní zámek aktualizace na úrovni řádku v obou tabulkách zbraně a špioni pro id=1 řádek (2 řádky celkem, 1 řádek v každé tabulce). To lze dokázat tak, že P2 začne spouštět Q3, dostane se na místo 1, ale zablokuje se na místě 2 a bude uvolněn, až když P1 zavolá COMMIT. Všechno, co jsem právě řekl o P2 běžícím Q3, platí pro P2 běžícím Q4. Stručně řečeno, na obrazovce P2 místo2 zamrzne, dokud nebude P1 Commit.
Ještě jedna poznámka o implicitních transakcích. Vaše skutečné Dotaz Q1 to provede velmi rychle a jeho výstup provede implicitní potvrzení. Předchozí odstavec to však rozebírá, pokud máte spuštěny časově náročnější rutiny.
2. otázka: Když P1 začne začínat Q2 a dostane se na místo2, získal exkluzivní zámek aktualizace na úrovni řádku v obou tabulkách zbraně a špioni pro id=1 řádek (2 řádky celkem, 1 řádek v každé tabulce). P2 však nemá žádné problémy s blokováním weapons
ve 3. čtvrtletí , ale P2 má problémy se spuštěním Q4 na place2 spies
.
Takže rozdíly mezi Q1 a Q2 se týkají MySQL, protože ví, že FK index není relevantní pro sloupec v UPDATE, a manuál uvádí, že v Note1 níže.
Když P1 spustí Q1, P2 nemá žádné problémy s typy dotazů Q5 bez uzamčení pouze pro čtení. Jediným problémem je, jaká data P2 vidí na základě zavedené ÚROVNĚ IZOLACE.
Poznámka 1 :Z manuálové stránky MySQL nazvané Zámky nastavené různými Příkazy SQL v InnoDB :
Výše uvedené je důvodem chování Q2: je takový, že P2 může volně provádět UPDATE nebo získat UPDATE exkluzivní dočasné uzamčení weapons
. Je to proto, že engine neprovádí UPDATE s P1 na id_zbroje, a proto v této tabulce nemá zámek na úrovni řádku.
Abychom to vrátili zpět na 50 000 stop, největší starostí je doba, po kterou je zámek držen buď v implicitní transakci (bez START/COMMIT), nebo v explicitní transakci před COMMIT. Peer procesu může být teoreticky zakázáno získávat jeho potřebu AKTUALIZACE na dobu neurčitou. Ale každý pokus o získání tohoto zámku se řídí jeho nastavením pro innodb_lock_wait_timeout . To znamená, že ve výchozím nastavení vyprší časový limit asi po 60 sekundách. Chcete-li zobrazit své nastavení, spusťte:
select @@innodb_lock_wait_timeout;
Pro mě je to v tuto chvíli 50 (sekund).