Pertimbangkan skema berikut:(Sisa stmt tersisa untuk kenyamanan Anda) :
-- 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;
Sekarang, kami memiliki 2 proses, P1 dan P2. Terbaik untuk menguji di mana P1 mungkin adalah MySQL Workbench dan P2 adalah jendela baris Perintah MySql. Dengan kata lain, Anda harus mengatur ini sebagai koneksi yang terpisah dan benar. Anda harus memiliki perhatian yang cermat untuk menjalankan langkah demi langkah ini dengan cara yang benar (dijelaskan dalam Narasi bawah) dan lihat dampaknya pada jendela proses lainnya.
Pertimbangkan kueri berikut, dengan mengingat bahwa kueri mysql yang tidak dibungkus dalam transaksi eksplisit itu sendiri merupakan transaksi implisit. Tapi di bawah, saya mengayunkan untuk eksplisit:
P1:
START TRANSACTION;
-- place1
UPDATE spies SET name = 'Bond', weapon_id = 1 WHERE id = 1;
-- place2
COMMIT;
P2:
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 (gado-gado pertanyaan):
SELECT * from weapons;
SELECT * from spies;
Narasi
Q1: Saat P1 dimulai Q1 , dan sampai ke place2, ia telah memperoleh kunci pembaruan tingkat baris eksklusif di kedua tabel senjata dan mata-mata untuk baris id=1 (total 2 baris, 1 baris di setiap tabel). Hal ini dapat dibuktikan dengan P2 mulai menjalankan Q3, sampai ke tempat1, tetapi memblokir di tempat2, dan baru dibebaskan ketika P1 berkeliling untuk memanggil COMMIT. Semua yang baru saja saya katakan tentang P2 yang menjalankan Q3 sama dengan P2 yang menjalankan Q4. Singkatnya, di layar P2, place2 berhenti sampai P1 Komit.
Catatan lagi tentang transaksi implisit. Anda yang asli Kueri Q1 akan melakukan ini dengan sangat cepat dan keluar darinya akan melakukan komit implisit. Namun, paragraf sebelumnya memecahnya jika Anda menjalankan rutinitas yang memakan waktu lebih banyak.
T2: Saat P1 mulai dimulai Q2 , dan sampai ke place2, ia telah memperoleh kunci pembaruan tingkat baris eksklusif di kedua tabel senjata dan mata-mata untuk baris id=1 (total 2 baris, 1 baris di setiap tabel). Namun, P2 tidak memiliki masalah dengan pemblokiran Q3 weapons
, tetapi P2 memiliki masalah pemblokiran saat menjalankan Q4 di place2 spies
.
Jadi, perbedaan antara Q1 dan Q2 turun ke MySQL mengetahui bahwa indeks FK tidak relevan dengan kolom di UPDATE, dan manual menyatakan bahwa di Note1 di bawah.
Ketika P1 menjalankan Q1, P2 tidak memiliki masalah jenis kueri Q5 yang hanya-baca dan tidak terkunci. Satu-satunya masalah adalah apa yang dilihat oleh data rendition P2 berdasarkan ISOLATION LEVEL yang ada.
Catatan1 :Dari Halaman Manual MySQL berjudul Kunci Ditetapkan oleh Berbeda Pernyataan SQL di InnoDB :
Di atas adalah mengapa perilaku Q2: sedemikian rupa sehingga P2 bebas melakukan UPDATE atau memperoleh kunci sesaat eksklusif UPDATE pada weapons
. Ini karena mesin tidak melakukan UPDATE dengan P1 pada weapon_id dan dengan demikian tidak memiliki kunci tingkat baris di tabel itu.
Untuk menarik ini kembali ke 50.000 kaki, kekhawatiran terbesar seseorang adalah durasi di mana kunci diadakan baik dalam transaksi implisit (satu tanpa START/COMMIT), atau transaksi eksplisit sebelum COMMIT. Proses peer dapat dilarang untuk memperoleh kebutuhannya akan UPDATE secara teori tanpa batas. Tetapi setiap upaya untuk memperoleh kunci itu diatur oleh pengaturannya untuk innodb_lock_wait_timeout . Artinya, secara default, setelah sekitar 60 detik waktu habis. Untuk melihat setelan Anda, jalankan:
select @@innodb_lock_wait_timeout;
Bagi saya, saat ini, 50 (detik).