Tìm hiểu về các loại Khoá (Explicit Locking) trong PostgreSQL

Tìm hiểu về các loại Khoá (Explicit Locking) trong PostgreSQL

Threads
  • Ơ buồn cười thật. Ai cũng biết GIF là định dạng ảnh động thường được dùng thay cho video clip để hiển thị các nội dung ngắn trên nền tảng web. GIF tiện hơn các nội dung dạng video là vì nó được hiển thị như một bức ảnh và được hỗ trợ rộng rãi. Cơ mà GIF có dung lượng nặng quá.

    Nói thật nhiều lúc mình có vài cái hành động muốn hiển thị lên web cho mọi người xem, cơ mà định dạng GIF nó nặng với cả cũng không biết cách tối ưu cho nhẹ xuống. Hôm nay lên mạng tìm hiểu xem định dạng nào có khả năng thay thế GIF trong tương lai thì mọi người biết đó là gì không? Là WEBP (webp)!!! Đúng vậy, là định dạng ảnh mà mình đang dùng trên blog lâu nay luôn á, mà giờ mới biết là nó hiển thị được cả ảnh động nữa, hơi quê 😆

    Kết hợp với ffmpeg nữa là chuyển được tất tần tật video clip thành webp được ngay. Để vài nửa ngồi chế lại cái cli một tí là dùng ngon luôn mọi người ạ 🤪

    » Xem thêm
  • Cảm giác như Github Copilot đang cố gắng mở rộng thị trường cho anh em developer á. Mới trước họ ra mắt Github Open Copilot Chat thì mới đây lại thêm cái Using GitHub Copilot in the command line dùng để giải thích hoặc gợi ý lệnh trong terminal.

    Đây, cách dùng rất đơn giản thôi, ví dụ muốn nó giải thích câu lệnh sudo apt-get để làm gì, thì:

    $ gh copilot explain "sudo apt-get"

    Hoặc nhờ nó gợi ý lệnh mong muốn, sử dụng tiếng Việt được luôn nhé (kể cả tiếng Việt không dấu vẫn hiểu 😳)

    $ gh copilot suggest "xoá commit chưa push"

    Mình đã kiểm tra và thấy lệnh ra rất đúng, xịn thật 🤓

    » Xem thêm
  • Github có chương trình học và ôn thi để lấy chứng chỉ "ghim" vào hồ sơ cá nhân. Các chứng chỉ này xoay quanh kỹ năng sử dụng và làm việc thành thạo với git cũng như Github. Nếu bạn muốn học thêm kỹ năng mới đồng thời thu thập thêm badge cho mình thì còn chần chừ gì nữa 👇

    Showcase your expertise with GitHub Certifications

    » Xem thêm

Vấn đề

Làm việc với SQL hay PostgreSQL đủ lâu nhưng có bao giờ bạn đặt câu hỏi sẽ thế nào nếu như thực hiện một lệnh SELECT và DROP trên cùng một table cùng lúc? Lệnh nào sẽ chạy trước lệnh nào sẽ chạy sau, độ ưu tiên của các câu lệnh như thế nào hay là PostgreSQL dựa vào đâu để phân mức ưu tiên? Bài viết này hôm nay tôi xin phép trình bày cách mà PostgreSQL sử dụng Khoá (Locks) để giải quyết xung đột dữ liệu như thế nào nhé.

Tại sao lại cần khoá?

PostgreSQL cung cấp nhiều chế độ khóa khác nhau để kiểm soát quyền truy cập đồng thời vào dữ liệu trong bảng. Các khoá này có thể được sử dụng để can thiệp vào các tình huống của MVCC (Multi Version Concurrency Control).

Ngoài ra, hầu hết các lệnh PostgreSQL có được các khóa của các chế độ thích hợp để đảm bảo rằng các bảng được tham chiếu không bị xóa hoặc sửa đổi theo cách không mong muốn trong khi các lệnh đang được thực thi. Ví dụ như lệnh TRUNCATE không thể thực hiện đồng thời với các lệnh thao tác khác trên cùng một bảng như SELECT..., để làm được điều TRUNCATE được cấp phát cho một khoá gọi là ACCESS EXCLUSIVE.

Các cấp khoá

Postgres có các cấp khoá sau đây:

  • Table-Level Locks
  • Row-Level Locks
  • Page-Level Locks
  • Advisory Locks

Các cấp khoá mô tả miền xung đột của các lệnh PostgreSQL ở các cấp độ bảng (table), dòng (row) hay là trang (page)...

Tuy nhiên trong bài viết này tôi xin phép trình bày hai cấp khoá là Table và Row. Bạn đọc có thể tìm hiểu thêm các loại khoá tại trang tài liệu của PostgreSQL.

Khoá cấp bảng (Table-Level Locks)

Là các khoá ở quy mô bảng, các khoá này được cấp phát tự động hoặc thông qua lệnh LOCK.

Tự động có nghĩa là phụ thuộc vào lệnh SQL nào khi gọi thì bạn ngay lập tức sẽ được cấp pháp khoá đó. Dưới đây là một số câu lệnh quen thuộc và các khoá được cấp tự động tương ứng khi bạn gọi chúng.

  • SELECT: ACCESS SHARE
  • UPDATE, DELETE, INSERT: ROW EXCLUSIVE
  • CREATE INDEX: SHARE
  • CREATE TRIGGER: SHARE ROW EXCLUSIVE
  • DROP TABLE, TRUNCATE: ACCESS EXCLUSIVE

Nhiều khoá và chi tiết hơn xem lại trang tài liệu của postgres.

Dưới đây là bảng thể hiện sự xung đột của các khoá với nhau.

table locking

Tôi có thể giải thích như sau: nhìn vào bảng chúng ta thấy khoá ACCESS SHARE sẽ xung đột với ACCESS EXCLUSIVE vì thế trong các transaction nếu lệnh nào đang được thực hiện trước (nắm khoá ACCESS SHARE) thì lệnh sau (nắm khoá ACCESS EXCLUSIVE) phải chờ cho đến khi transaction được hoàn thành mới có thể tiếp tục và ngược lại.

-- (1)
BEGIN; 
-- (2)
SELECT * FROM users; -- ACCESS SHARE LOCKS
-- (4)
COMMIT;
-- (3)
TRUNCATE users; -- ACCESS EXCLUSIVE LOCKS

Hãy thử chạy các lệnh trên trên hai tiến trình khác nhau theo các bước (1) (2) (3) (4) để xem điều gì xảy ra nhé.

Khoá cấp hàng (Row-Level Locks)

Các khoá cấp hàng được cấp phát bằng cách xác định tên của khoá trong câu truy vấn. Có 4 khoá là:

  • FOR UPDATE
  • FOR NO KEY UPDATE
  • FOR SHARE
  • FOR KEY SHARE

row locking

FOR UPDATE khiến các hàng được truy xuất bởi SELECT bị khóa như thể để cập nhật. Điều này giúp chúng không bị khóa, sửa đổi hoặc xóa bởi các transaction khác cho đến khi transaction hiện tại kết thúc. Nghĩa là, các transaction khác như DELETE hoặc UPDATE một trong số các hàng này sẽ bị chặn cho đến khi transaction hiện tại kết thúc.

Tương tự như Table-Level Locks, bảng trên mô tả xung đột giữa các khoá. Các khoá xung đột với nhau sẽ phải đợi cho đến khi khoá cấp phát trước được thực hiện xong thì mới đến lượt mình.

Ví dụ bạn phát triển một tính năng đổi quà, có một bảng quà chứa số lượng còn lại của quà muốn đổi và bảng lưu số điểm hợp lệ của bạn dùng để đổi quà. Khi đổi quà bạn cần lấy ra số lượng quà còn lại và số điểm của bạn, kiểm tra qua nhiều điều kiện khắc nghiệt và tốn rất nhiều thời gian nữa mới có thể đổi. Giả sử trong lúc yêu cầu thứ nhất đã lấy ra số lượng quà còn lại là 1 và có yêu cầu thứ hai ngay lập tức cũng lấy ra số lượng quà còn lại là 1 thì điều gì sẽ xảy ra nếu như cả hai tiếp tục đổi quà? Để ngăn chặn điều đó bạn có thể sử dụng Row-Level Locks, tức là khi một transaction đang lấy số lượng quà còn lại để bắt đầu validate thì transaction thứ hai cần chờ đợi cho đến khi transaction đầu kết thúc.

Deadlock

Deadlock xảy ra khi hai hoặc nhiều transaction giữ các khoá mà bên kia mong muốn. Ví dụ transaction thứ nhất có được khoá ACCESS EXCLUSIVE trên bảng A và sau đó muốn có tiếp khoá đó trên bảng B trong khi transaction thứ hai đã có khoá ACCESS EXCLUSIVE trên bảng B và bây giờ lại muốn có khoá đó trên bảng A thì lúc đó không có transaction nào có thể tiếp tục. PostgreSQL tự động phát hiện tình huống này và giải quyết bằng cách huỷ bỏ một trong các transaction có liên quan, transaction bị huỷ bỏ không thể đoán trước.

Deadlock cũng có thể xảy ra ở trong các khoá cấp hàng khi các transaction cũng giữ khoá của nhau.

Biện pháp bảo vệ tốt nhất chống lại các deadlock nói chung là tránh để cho các lệnh có được các khóa trên nhiều đối tượng (table/row) theo một thứ tự xác định.

Nếu transaction được thực hiện trên nhiều đối tượng liên quan, cách tốt nhất là làm sao cho thời gian thực hiện transaction càng ngắn càng tốt. Tránh giữ các transaction trong thời gian dài. Ví dụ cho một thực hành tồi là transaction sẽ được thực thi tiếp cho đến khi chờ đợi thông tin nhập của người dùng xong.

Tổng kết

Bài viết trên đây tôi đã trình bày về cách mà PostgreSQL sử dụng khoá để quản lý quyền truy cập đồng thời vào dữ liệu trong bảng. Mặc dù là dành riêng cho PostgreSQL nhưng tư tưởng sử dụng khoá vẫn tồn lại trong các loại cơ sở dữ liệu SQL khác như MySQL, SQL Server... Nắm được cách hoạt động của khoá sẽ giúp bạn ứng biến với những tình huống trong việc phát triển ứng dụng cùng SQL.

hoặc
* Bản tin tổng hợp được gửi mỗi 1-2 tuần, huỷ bất cứ lúc nào.
Author

Xin chào, tôi tên là Hoài - một anh Dev kể chuyện bằng cách viết ✍️ và làm sản phẩm 🚀. Với nhiều năm kinh nghiệm lập trình, tôi đã đóng góp một phần công sức cho nhiều sản phẩm mang lại giá trị cho người dùng tại nơi đang làm việc, cũng như cho chính bản thân. Sở thích của tôi là đọc, viết, nghiên cứu... Tôi tạo ra trang Blog này với sứ mệnh mang đến những bài viết chất lượng cho độc giả của 2coffee.dev.Hãy theo dõi tôi qua các kênh LinkedIn, Facebook, Instagram, Telegram.

Bạn thấy bài viết này có ích?
Không

Bình luận (1)

Nội dung bình luận...
Avatar
Trần Ngọc Hải2 năm trước
Bài viết quá hay quá chi tiết cảm ơn tác giả
Trả lời