Khóa (lock) là cơ chế kiểm soát truy cập đồng thời vào tài nguyên chung nhằm đảm bảo tính toàn vẹn và nhất quán dữ liệu khi nhiều luồng hoặc giao dịch thao tác song song. Trong MySQL, hành vi khóa phụ thuộc mạnh vào bộ lưu trữ (storage engine) được sử dụng — mỗi loại hỗ trợ một hoặc nhiều mức độ granular lock khác nhau.
Dưới đây là sự phân bố khóa theo engine tiêu biểu:
- MyISAM và MEMORY: chỉ hỗ trợ khóa bảng (table-level lock)
- InnoDB: chủ yếu dùng khóa hàng (row-level lock), nhưng cũng hỗ trợ khóa bảng khi cần
- BDB (Berkeley DB, đã bị loại bỏ từ MySQL 5.1 nhưng vẫn có giá trị tham khảo): hỗ trợ cả khóa trang (page-level lock) và khóa hàng
So sánh đặc điểm ba loại khóa
- Khóa hàng
- Ưu điểm: Độ chi tiết cao → xác suất xung đột khóa thấp → hiệu năng đồng thời tốt
- Nhược điểm: Chi phí quản lý lớn, thời gian cấp khóa chậm hơn, dễ phát sinh deadlock do phải duy trì nhiều khóa nhỏ lẻ
- Khóa bảng
- Ưu điểm: Chi phí thấp, cấp khóa nhanh, không thể xảy ra deadlock vì toàn bộ bảng được khóa cùng lúc
- Nhược điểm: Độ chi tiết thô → dễ gây tắc nghẽn khi có nhiều truy vấn đọc/ghi xen kẽ
- Khóa trang
- Là giải pháp trung gian: chi phí và thời gian cấp khóa nằm giữa khóa bảng và khóa hàng
- Độ chi tiết ở mức khối dữ liệu (thường ~16KB), nên khả năng xung đột và mức độ song song đều ở mức trung bình
- Vẫn có thể xuất hiện deadlock do khóa từng trang riêng lẻ
Khóa bảng trong MyISAM
MyISAM áp dụng khóa bảng theo hai chế độ: - Khóa đọc chia sẻ (shared read lock): Nhiều phiên có thể đọc đồng thời mà không cản trở nhau. - Khóa ghi độc quyền (exclusive write lock): Khi một phiên đang ghi, mọi phiên khác — dù đọc hay ghi — đều bị chặn cho đến khi khóa được giải phóng. Một điểm đặc biệt của MyISAM là chèn đồng thời (concurrent insert), điều khiển bởi biến hệ thốngconcurrent_insert:
0: Tắt hoàn toàn chèn đồng thời1: Cho phép chèn vào cuối bảng nếu không có khoảng trống do xóa trước đó2: Luôn cho phép chèn vào cuối bảng, bất kể tình trạng phân mảnh
LOCK TABLES orders READ;
-- hoặc
LOCK TABLES customers WRITE;
Và giải phóng bằng:
UNLOCK TABLES;
Do khóa được cấp toàn bộ ngay từ đầu (all-or-nothing), MyISAM không bao giờ rơi vào trạng thái deadlock.
Khóa hàng trong InnoDB
InnoDB thực hiện khóa hàng dựa trên các mục trong chỉ mục (index entries). Nếu truy vấn sử dụng chỉ mục phù hợp (ví dụ:WHERE id = ? với id là khóa chính), chỉ các hàng thỏa mãn mới bị khóa. Ngược lại, nếu không dùng chỉ mục (hoặc dùng chỉ mục không hiệu quả), InnoDB sẽ khóa toàn bộ bảng dưới dạng khóa hàng ảo — dẫn đến hiệu năng tương đương khóa bảng.
Hai loại khóa hàng chính:
- Shared Lock (S): Cho phép đọc, ngăn các giao dịch khác lấy khóa X trên cùng tập dữ liệu.
- Exclusive Lock (X): Cho phép cập nhật/xóa, ngăn cả khóa S lẫn X từ các giao dịch khác.
IS(Intention Shared): Báo hiệu rằng giao dịch định đặt khóa S lên một số hàng trong bảng.IX(Intention Exclusive): Báo hiệu rằng giao dịch định đặt khóa X lên một số hàng trong bảng.
-- Đặt khóa S lên hàng có order_id = 1001
SELECT * FROM orders WHERE order_id = 1001 LOCK IN SHARE MODE;
-- Đặt khóa X lên hàng có order_id = 1002
SELECT * FROM orders WHERE order_id = 1002 FOR UPDATE;
Deadlock trong InnoDB thường xảy ra khi hai giao dịch lần lượt khóa các hàng theo thứ tự ngược nhau và chờ nhau giải phóng — ví dụ: giao dịch A khóa hàng 1 rồi chờ hàng 2, trong khi giao dịch B khóa hàng 2 rồi chờ hàng 1.