Giới thiệu về giao dịch
Giao dịch là một tập hợp các thao tác được xem như một đơn vị công việc duy nhất, không thể tách rời. Giao dịch thực hiện tất cả các thao tác như một thể thống nhất, cùng nhau gửi hoặc hủy bỏ yêu cầu đến hệ thống. Tức là các thao tác này hoặc cùng thành công, hoặc cùng thất bại.
Lưu ý: Theo mặc định, MySQL thực hiện giao dịch với chế độ tự động commit. Điều này có nghĩa là khi thực thi một câu lệnh DML, MySQL sẽ ngay lập tức commit giao dịch.
Ví dụ: Trong chuyển khoản ngân hàng, việc trừ 1000 từ tài khoản của Trương Tam và cộng 1000 vào tài khoản của Lý Tứ phải hoàn thành cùng lúc. Nếu một bước thất bại, toàn bộ giao dịch sẽ được rollback, đảm bảo không mất tiền. Toàn bộ quá trình này là một giao dịch, như vậy sẽ không xảy ra trường hợp Trương Tam bị trừ 1000 nhưng do sự cố hệ thống, Lý Tứ không nhận được 1000.
Các thao tác với giao dịch
Thay đổi cách commit giao dịch [Ảnh hưởng đến toàn bộ mã hiện tại]
Xem / Thiết lập chế độ commit giao dịch
SELECT @@autocommit
SET @@autocommit = 0
Thực thi:
SELECT @@autocommit;
Kết quả:
[@@autocommit có giá trị là 1, tức là giao dịch tự động commit theo mặc định]
Thực thi:
SET @@autocommit = 0
[Khi truy vấn lại, thấy giá trị của @@autocommit đã thay đổi thành 0]
Commit giao dịch
COMMIT
Chúng ta đã đặt @@autocommit thành 0, nên việc tự động commit giao dịch đã bị tắt. Bây giờ chúng ta thực hiện thao tác chuyển tiền:
-- Người gửi -1000
UPDATE tai_khoan SET so_du = so_du - 1000 WHERE ten = 'Nguyen Van A';
-- Người nhận +1000
UPDATE tai_khoan SET so_du = so_du + 1000 WHERE ten = 'Tran Thi B';
Kết quả truy vấn tài khoản:
[Tại sao số dư tài khoản của cả hai người đều không thay đổi? Lý do là chúng ta đã tắt tự động commit giao dịch, những thay đổi này đều là tạm thời, kết quả thao tác chưa được commit vào cơ sở dữ liệu, lúc này chúng ta cần commit thủ tục giao dịch]
Commit giao dịch:
COMMIT;
Rollback giao dịch
ROLLBACK
Khi một bước nào đó gặp lỗi dẫn đến toàn bộ thao tác không hoàn chỉnh, chúng ta không nên commit giao dịch, mà cần thực hiện thủ tục để quay về trạng thái ban đầu, tức là rollback giao dịch.
Thực thi:
ROLLBACK;
Không thay đổi cách commit giao dịch [Không ảnh hưởng đến toàn bộ mã hiện tại]
Bắt đầu giao dịch
START TRANSACTION hoặc START
Commit giao dịch
COMMIT
Rollback giao dịch
ROLLBACK
Bốn đặc tính cơ bản của giao dịch (ACID)
Tính nguyên tử (Atomicity)
Nội dung: Giao dịch là một thể thống nhất không thể tách rời, hoặc thực thi hoàn toàn thành công, hoặc hoàn toàn thất bại và rollback.
Ví dụ: Trong chuyển khoản ngân hàng, việc trừ tiền từ tài khoản A và cộng tiền vào tài khoản B phải hoàn thành cùng lúc. Nếu một bước thất bại, toàn bộ giao dịch sẽ được rollback, đảm bảo không mất tiền.
Tính nhất quán (Consistency)
Nội dung: Trước và sau khi thực thi giao dịch, cơ sở dữ liệu chuyển từ trạng thái hợp lệ sang trạng thái hợp lệ khác, các ràng buộc toàn vẹn dữ liệu (như khóa chính duy nhất, trường không được rỗng, v.v.) phải được đảm bảo.
Ví dụ: Trước và sau khi chuyển tiền, tổng số dư của tài khoản A và B không đổi, không xuất hiện tình trạng tiền tự nhiên tăng hoặc giảm.
Tính cô lập (Isolation)
Nội dung: Khi nhiều giao dịch thực thi đồng thời, chúng cách ly lẫn nhau, không can thiệp vào nhau, mỗi giao dịch như đang thao tác độc lập với cơ sở dữ liệu.
Cấp độ (từ thấp đến cao): Đọc chưa commit (Read Uncommitted), Đọc đã commit (Read Committed), Đọc lặp lại (Repeatable Read) (cấp độ mặc định), Serial hóa (Serializable).
Ví dụ: Nếu giao dịch A đang đọc dữ liệu, giao dịch B đồng thời sửa đổi dữ liệu đó, tính cô lập đảm bảo A không đọc được dữ liệu ở trạng thái trung gian.
Tính bền vững (Durability)
Nội dung: Một khi đã commit, các sửa đổi của giao dịch đối với cơ sở dữ liệu sẽ được lưu vĩnh viễn, ngay cả khi hệ thống bị hỏng hoặc mất điện cũng không bị mất.
Vấn đề với giao dịch đồng thời
Đọc bẩn (Dirty Read)
| Vấn đề | Mô tả |
|---|---|
| Đọc bẩn | Một giao dịch đọc được dữ liệu mà một giao dịch khác chưa commit |
Đọc không lặp lại (Non-repeatable Read)
| Vấn đề | Mô tả |
|---|---|
| Đọc không lặp lại | Một giao dịch đọc cùng một bản ghi nhiều lần, nhưng dữ liệu đọc được hai lần khác nhau |
Đọc ảo (Phantom Read)
| Vấn đề | Mô tả |
|---|---|
| Đọc ảo | Một giao dịch truy vấn dữ liệu theo điều kiện, không tìm thấy bản ghi tương ứng, nhưng khi chèn dữ liệu lại phát hiện bản ghi đó đã tồn tại, giống như xuất hiện một "ma" |
Cấp độ cô lập giao dịch (Để giải quyết vấn đề giao dịch đồng thời)
Cấp độ (từ thấp đến cao): Đọc chưa commit (Read Uncommitted), Đọc đã commit (Read Committed), Đọc lặp lại (Repeatable Read) (cấp độ mặc định), Serial hóa (Serializable).
Cấp độ từ thấp đến cao, tính bảo mật cũng ngày càng cao, nhưng hiệu suất sẽ ngày càng giảm, do đó khi sử dụng cần cân bằng giữa tính bảo mật và hiệu suất.
Xem cấp độ cô lập giao dịch
SELECT @@TRANSACTION_ISOLATION
Thực thi:
SELECT @@TRANSACTION_ISOLATION
Kết quả:
Thấy được: Đọc lặp lại (Repeatable Read) là cấp độ mặc định
Thiết lập cấp độ cô lập giao dịch
SET [ SESSION | GLOBAL ] TRANSACTION ISOLATION LEVEL
[ READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE ]
Sự khác biệt giữa SESSION và GLOBAL:
- SESSION có nghĩa là cấp độ phiên, chỉ hiệu quả với cửa sổ client hiện tại
- GLOBAL có nghĩa là cấp độ toàn cầu, hiệu quả với tất cả các cửa sổ client