Hãy xem xét lược đồ sau: (Rem stmts để thuận tiện cho bạn) :
-- 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;
Bây giờ, chúng ta có 2 quy trình, P1 và P2. Tốt nhất để kiểm tra nơi P1 có lẽ là MySQL Workbench và P2 là cửa sổ dòng lệnh MySql. Nói cách khác, bạn phải thiết lập điều này thành các kết nối riêng biệt và đúng. Bạn sẽ phải có con mắt tỉ mỉ để từng bước chạy chúng theo cách thích hợp (được mô tả trong Tường thuật bên dưới) và xem tác động của nó đối với cửa sổ quy trình khác.
Hãy xem xét các truy vấn sau, hãy nhớ rằng một truy vấn mysql không được bao bọc trong một giao dịch rõ ràng, bản thân nó là một giao dịch ngầm. Nhưng bên dưới, tôi đã phản đối:
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 (hàng loạt truy vấn):
SELECT * from weapons;
SELECT * from spies;
Tường thuật
Q1: Khi P1 bắt đầu bắt đầu Q1 và đến được vị trí 2, nó đã nhận được khóa cập nhật cấp độ hàng độc quyền trong cả vũ khí và gián điệp của bảng cho id =1 hàng (tổng cộng 2 hàng, mỗi bảng 1 hàng). Điều này có thể được chứng minh bằng việc P2 bắt đầu chạy Q3, đến địa điểm1, nhưng chặn ở địa điểm2 và chỉ được giải phóng khi P1 chuyển sang gọi COMMIT. Mọi thứ tôi vừa nói về P2 chạy Q3 là ditto cho P2 chạy Q4. Tóm lại, trên màn hình P2, place2 đóng băng cho đến khi Cam kết P1.
Một lưu ý một lần nữa về các giao dịch ngầm. Thực của bạn Truy vấn Q1 sẽ thực hiện điều này rất nhanh và việc thoát ra khỏi nó sẽ thực hiện một cam kết ngầm. Tuy nhiên, đoạn trước đã chia nhỏ nó là bạn phải chạy các quy trình tốn kém thời gian hơn.
Câu hỏi 2: Khi P1 bắt đầu bắt đầu Q2 và đến được vị trí 2, nó đã nhận được khóa cập nhật cấp độ hàng độc quyền trong cả vũ khí và gián điệp của bảng cho id =1 hàng (tổng cộng 2 hàng, mỗi bảng 1 hàng). Tuy nhiên, P2 không gặp vấn đề gì với vũ khí weapons
chặn Q3 , nhưng P2 có vấn đề về khối khi chạy Q4 tại place2 spies
.
Vì vậy, sự khác biệt giữa Q1 và Q2 do MySQL biết rằng chỉ mục FK không liên quan đến một cột trong CẬP NHẬT và hướng dẫn sử dụng nêu rõ điều đó trong Note1 bên dưới.
Khi P1 chạy Q1, P2 không có vấn đề gì với các loại truy vấn Q5 truy vấn không khóa chỉ đọc. Vấn đề duy nhất là hiển thị dữ liệu P2 nhìn thấy gì dựa trên CẤP ĐỘ ISOLATION tại chỗ.
Lưu ý1 :Từ Trang hướng dẫn sử dụng MySQL có tên Các ổ khóa được đặt theo cách khác Câu lệnh SQL trong InnoDB :
Trên đây là lý do tại sao hành vi của Q2: để P2 có thể tự do thực hiện CẬP NHẬT hoặc có được một khóa tạm thời độc quyền CẬP NHẬT đối với vũ khí weapons
. Điều này là do công cụ không thực hiện CẬP NHẬT với P1 trên vũ khí_id và do đó không có khóa cấp hàng trong bảng đó.
Để kéo điều này trở lại 50.000 feet, mối quan tâm lớn nhất của một người là khoảng thời gian khóa được giữ trong một giao dịch ngầm (giao dịch không có START / COMMIT) hoặc giao dịch rõ ràng trước khi CAM KẾT. Về lý thuyết, một quy trình ngang hàng có thể bị cấm đạt được nhu cầu CẬP NHẬT của nó vô thời hạn. Nhưng mỗi nỗ lực để có được khóa đó bị điều chỉnh bởi cài đặt của nó cho innodb_lock_wait_timeout . Điều đó có nghĩa là, theo mặc định, sau khoảng 60 giây, nó sẽ hết thời gian chờ. Để xem cài đặt của bạn, hãy chạy:
select @@innodb_lock_wait_timeout;
Đối với tôi, hiện tại, nó là 50 (giây).