Noticias de Famosos

Cẩn thận, sql có thể kill transaction của bạn bất kỳ khi nào.

1. Deadlock xảy ra khi nào.

Deadlock là hiện tượng tranh chấp tài nguyên giữa hai hay nhiều lệnh trong đó lệnh này giữ tài nguyên mà lệnh kia cần dẫn tới việc không lệnh nào có thể kết thúc để giải phóng tài nguyên.

2. Ví dụ deadlock.

Một transaction được thực thi và hoàn tất khi và chỉ khi tất cả các lệnh trong một transaction được hoàn tất.

Deadlock trong database sẽ chỉ xảy ra khi có nhiều hơn một tài nguyên cần phải bị chiếm giữa hoàn tất giao dịch. Xét một câu trúc DB đơn giản như sau:

Thực hiện hai giao dịch đồng thời:

Giao dịch 1:

  • Insert bảng A
  • Insert bảng B

Giao dịch 2:

  • Select bảng B
  • Select bảng A Code demo: Transaction 1

Ở đây, trong giao dịch 1 ta để thêm lệnh Thread.Sleep(5000) để quan sát hiện tượng deadlock được rõ hơn. Thực hiện hai chương trình gần như đồng thời, chương trình của giao dịch 1 chạy trước, ngay sau là chương trình giao dịch 2 thì sẽ ghi nhận deadlock exception xảy ra.

Nguyên nhân xảy ra:

  • Giao dịch 1 vào trước chiếm giữ bảng A để insert, sau đó dừng 5s để tiếp tục chiếm giữa bảng B insert. Trong thời gian chờ bảng B hoàn toàn không bị lock. Vì trong một giao dịch nên lệnh Insert vào bảng A chưa kết thúc chừng nào lệnh insert bảng B kết thúc, bảng A bị giữ bởi T1.
  • Giao dịch 2 vào sau nhưng chiếm được bảng B để select trước, sau đó nó cần chiếm bảng A để tiếp tục select. Do trong cùng một giao dịch nên bảng B bị giữ chừng nào T2 chiếm được bảng A để thực hiện hoàn tất một giao dịch.

Như vậy cả T1 và T2 đều lock lẫn nhau và không thằng nào thoát ra được. Dẫn tới SQL Server buộc phải kill một trong hai giao dịch, trong trường hợp này là giao dịch T2 bị kill, T1 thực hiện bình thường.

Một điều cần lưu ý là nếu hai giao dịch trên chỉ có các lệnh insert và update, delete mà không có các lệnh select thì khả năng deadlock thấp hơn rất nhiều. Vì các lệnh insert và update chỉ lock row, do đó việc tranh chấp dẫn tới deadlock khó xảy ra.

3. Phải làm sao?

Không đảm bảo có thể loại bỏ hoàn toàn deadlock, nhưng áp dụng các chiến lược sau sẽ giúp việc xảy ra deadlock ít xảy ra hơn:

  • Giảm thiểu số lượng bảng cần tác động trong một giao dịch, giao dịch có số bảng tham gia càng ít thì khả năng xảy ra deadlock càng thấp.
  • Kiểm soát việc thưc thi các giao dịch sau cho thứ tự tác động các bảng là giống nhau như vậy sẽ chỉ xảy ra hiện tượng lock chứ không xảy ra hiện tượng deadlock.
  • Thực hiện giao dịch dạng batch thay vì gọi nhiều lần từ trong ứng dụng tới database. Nghĩa là thay vì gọi rời rạc thì generate ra một script duy nhất rồi gửi vào database hoặc gọi store procedure để thực thi giao dịch. Việc này giúp giảm thiếu deadlock vì hai lý do sau:
  • Giảm thời gian round trip qua đường mạng do việc gọi đi gọi lại do đó giao dịch kết thúc nhanh hơn.
  • Việc gửi script dạng batch, hoặc thực thi store procedure giúp sql server phân tích được toàn bộ mã script từ đó tạo ra một execution plan hiệu quả, khả năng tránh deadlock cao hơn. Không như việc gọi thực thi nhiều lần từ trong ứng dụng, SQL Server không thể biết sau lệnh thứ nhất thì lệnh tiếp theo là gì do đó không thể tạo ra chiến lược giải quyết deadlock. Cùng là ví dụ trên nhưng nếu để thành store procedure và thực thi đồng thời thì hiện tượng deadlock không xảy ra

Mặc dù store procedure Test1 có thời gian delay lâu hơn 10 giây, nhưng hiện tượng deadlock vẫn không xảy ra.

  • Tránh tương tác khi thực thi giao dịch để đảm bảo giao dịch thực thi nhanh nhất có thể. Ví dụ: insert vào bảng A, chờ xác nhận người dùng, insert vào bảng B rồi hoàn tất.
  • Sử dụng các mức độ lock phù hợp (Isolation Level).

4. Cụ thể hơn?

Thích cụ thể hơn thì xem bài viết khác về transaction nhé. :))

Có thể bạn quan tâm

Cùng tìm hiểu những điều cơ bản về MySQL Transaction

Tổng kết: trong bài này, mình sẽ giới thiệu về MySQL transaction và cách sử dụng câu lệnh COMMIT và ROLLBACK để q...