aedev.net
  • Trang chủ
  • AI
  • Mobile
  • Flutter
  • React Native
  • Backend
  • DevOps
  • Hướng dẫn
No Result
View All Result
SAVED POSTS
aedev.net
  • Trang chủ
  • AI
  • Mobile
  • Flutter
  • React Native
  • Backend
  • DevOps
  • Hướng dẫn
No Result
View All Result
aedev.net
No Result
View All Result
Minh họa kiến trúc backend API gọn gàng cho sản phẩm nhỏ

Optimistic locking trong PostgreSQL: tránh ghi đè thay đổi của người khác

Suong Nguyen by Suong Nguyen
23/10/2026
in Backend
0
585
SHARES
3.2k
VIEWS
Summarize with ChatGPTShare to Facebook

Hai thành viên cùng mở một ghi chú công việc. Người thứ nhất sửa nội dung rồi lưu. Người thứ hai vẫn nhìn bản cũ, sửa thêm một câu và bấm lưu sau đó. Nếu backend chỉ cập nhật theo ID, nội dung mới của người thứ nhất có thể bị thay thế mà không ai nhận ra.

Optimistic locking giải quyết tình huống này bằng một điều kiện: chỉ chấp nhận bản sửa nếu dữ liệu vẫn ở phiên bản mà người sửa đã đọc. Bài dùng PostgreSQL 17 làm mốc tài liệu, đối chiếu ngày 23/10/2026. Các câu SQL dành cho database thử riêng; ví dụ này chưa được chạy trên PostgreSQL trong lượt biên tập, nên các kết quả bên dưới là hành vi dự kiến để bạn kiểm tra.

Version phải đi cùng nội dung được đọc

Khi đọc ghi chú, backend trả cả nội dung và version. Client giữ version đó cùng bản nháp của biểu mẫu. Khi lưu, client gửi lại version đã đọc; backend kiểm tra nó trong cùng câu lệnh ghi, không dùng một lần SELECT kiểm tra rồi một câu UPDATE không điều kiện.

Ví dụ bảng nhỏ sau có một ghi chú thuộc workspace 7. workspace_id biểu diễn phạm vi mà backend đã kiểm tra quyền; không được tin giá trị workspace chỉ vì client gửi lên.

CREATE TABLE edit_demo (
  id bigint PRIMARY KEY,
  workspace_id bigint NOT NULL,
  body text NOT NULL,
  version bigint NOT NULL DEFAULT 1 CHECK (version > 0)
);

INSERT INTO edit_demo (id, workspace_id, body)
VALUES (1, 7, 'Ban dau');

SELECT id, body, version
FROM edit_demo
WHERE id = 1 AND workspace_id = 7;

Một cột updated_at vẫn hữu ích cho hiển thị thời gian nhưng dễ bị dùng sai làm mã phiên bản: độ chính xác, cách serialize và nguồn cập nhật thời gian có thể khác nhau. Cột số tăng rõ ràng giúp hợp đồng của ví dụ dễ kiểm tra hơn.

Gộp so sánh và cập nhật vào một câu lệnh

Giả sử cả hai người đều đọc được version 1. Lượt lưu đầu tiên thực hiện:

UPDATE edit_demo
SET body = 'Noi dung cua An', version = version + 1
WHERE id = 1 AND workspace_id = 7 AND version = 1
RETURNING id, body, version;

Nếu thành công, bản ghi trả về có version 2. Lượt lưu của người còn lại vẫn dùng điều kiện version 1 nên không cập nhật được hàng đó. Trong ứng dụng, thay các giá trị minh họa bằng bind parameter của driver; không ghép chuỗi SQL từ nội dung biểu mẫu.

Điểm quyết định là điều kiện version = ... nằm ngay trong UPDATE. Tài liệu PostgreSQL mô tả rằng ở Read Committed, khi gặp hàng được giao dịch khác cập nhật, câu lệnh chờ phù hợp rồi kiểm tra lại điều kiện trên phiên bản hàng đã cập nhật. Đây là cơ sở cho ví dụ một hàng này; không phải bảo đảm cho mọi bất biến liên quan nhiều bảng.

Không có hàng trả về cần được xử lý rõ

Backend phải đọc số hàng ảnh hưởng hoặc kết quả RETURNING. Không có hàng có thể do version cũ, bản ghi đã xóa, hoặc tài nguyên không còn nằm trong phạm vi mà người dùng được phép sửa. Đừng trả thành công chỉ vì driver không ném exception.

Sau khi kiểm tra phạm vi truy cập theo quy tắc của sản phẩm, trường hợp xung đột có thể được biểu diễn bằng phản hồi 409. Nếu thiết kế dùng If-Match và ETag như điều kiện HTTP, cần tuân theo semantics của precondition, thường có trường hợp 412. Không trộn hai hợp đồng mà không ghi rõ cho client.

Trên giao diện, giữ nguyên bản nháp của người dùng và cho họ xem bản mới nhất. Với đoạn văn dài, có thể hỗ trợ so sánh trước khi hợp nhất. Tự thay version cũ bằng version mới rồi gửi lại toàn bộ nội dung sẽ bỏ qua chính xung đột mà cơ chế này phát hiện.

Tự kiểm tra bằng hai phiên làm việc

Trong database thử, tạo bảng một lần rồi mở hai phiên cùng đọc version 1. Ở phiên A, bắt đầu transaction và chạy câu cập nhật nhưng chưa commit. Phiên B chạy cập nhật cùng ID và version cũ; kiểm tra việc chờ khóa. Commit A, rồi quan sát B không trả hàng phù hợp. Cuối cùng đọc lại dữ liệu: nội dung A phải còn nguyên và version bằng 2.

Thử thêm trường hợp A rollback: lúc đó B có thể tiếp tục cập nhật hàng còn version 1. Với Repeatable Read hoặc Serializable, phải xử lý cả lỗi serialization theo hợp đồng transaction; không suy rộng kết quả của Read Committed sang các isolation level khác.

Giới hạn và lỗi thường gặp

Mọi đường ghi đều phải tôn trọng version, kể cả script quản trị và tác vụ nền. Một đường ghi sửa nội dung nhưng quên tăng version sẽ làm client không phát hiện thay đổi. Các phép cập nhật nhiều hàng hoặc nhiều bảng còn cần transaction và ràng buộc phù hợp với bất biến nghiệp vụ.

Version không thay thế authorization. Nó cũng không ngăn gửi email hai lần hay tạo hai đơn hàng khi retry; đó là bài toán khác với chống mất cập nhật. Nếu chỉ cộng một bộ đếm, phép SET count = count + 1 có thể phù hợp hơn việc gửi lại giá trị tuyệt đối đã tính ở client.

Kết luận

Hãy xem version là lời hẹn giữa bản đọc và lần ghi tiếp theo. So sánh version trong câu cập nhật, kiểm tra kết quả thật và giữ bản nháp khi xung đột sẽ giúp người dùng giải quyết thay đổi mà không mất công việc đã làm.

Nguồn tham khảo

  • PostgreSQL 17: UPDATE và RETURNING
  • PostgreSQL 17: Transaction Isolation
  • RFC 9110: HTTP semantics và conditional requests

Tags: ConcurrencyOptimistic LockingPostgreSQL
SummarizeShare234
Suong Nguyen

Suong Nguyen

Related Stories

Minh họa kiến trúc backend API gọn gàng cho sản phẩm nhỏ

Idempotency-Key cho API tạo đơn: retry mà không tạo trùng nghiệp vụ

by Suong Nguyen
22/10/2026
0

Thiết kế phạm vi khóa, transaction và response lưu lại để API tạo đơn xử lý an toàn khi client gửi lại request.

Minh họa kiến trúc backend API gọn gàng cho sản phẩm nhỏ

Phân trang keyset trong PostgreSQL bằng created_at và id

by Suong Nguyen
21/10/2026
0

Dùng cặp created_at và id làm mốc phân trang, tránh thứ tự không xác định và hiểu giới hạn của keyset khi dữ liệu thay đổi.

Minh họa kiến trúc backend API gọn gàng cho sản phẩm nhỏ

Thiết kế backend API gọn gàng cho sản phẩm nhỏ

by admin
02/07/2026
0

Một backend API tốt cho sản phẩm nhỏ không cần quá phức tạp, nhưng phải rõ resource, validate kỹ, trả lỗi nhất quán và dễ mở rộng.

Minh họa AI hỗ trợ lập trình viên xây dựng sản phẩm phần mềm

AI đang thay đổi cách lập trình viên xây dựng sản phẩm

by admin
02/07/2026
0

AI không thay thế lập trình viên ngay lập tức, nhưng đang thay đổi cách chúng ta phân tích yêu cầu, viết code, review và vận hành sản...

Next Post
Minh họa pipeline CI/CD từ commit đến deploy cho team nhỏ

Node test runner hay Vitest: chọn theo cách dự án chạy code

0 0 votes
Article Rating
Subscribe
Login
Notify of
guest
guest
0 Comments
Oldest
Newest Most Voted
AE Dev

AE Dev mang đến các bài viết về lập trình, mobile app, backend, frontend, WordPress và công nghệ, phù hợp cho developer muốn học hỏi và cập nhật kiến thức thực tế.

Recent Posts

  • React Native: làm nút icon dễ sử dụng với VoiceOver và TalkBack
  • Phỏng vấn JavaScript: vì sao spread vẫn có thể làm đổi object gốc?
  • Android Photo Picker: chọn ảnh bằng URI và quản lý quyền đọc đúng vòng đời

Categories

  • AI
  • Backend
  • Đánh giá
  • DevOps
  • Flutter
  • Hướng dẫn
  • Lập trình Mobile
  • Phỏng vấn
  • React Native
  • Uncategorized

Weekly Newsletter

  • Buy JNews
  • Support Forum
  • Pre-sale Question
  • Contact Us

© 2026 AE Dev - Blog công nghệ, lập trình và chia sẻ kiến thức IT.

Welcome Back!

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In
No Result
View All Result
  • Trang chủ
  • AI
  • Mobile
  • React Native
  • Backend
  • DevOps
  • Hướng dẫn
  • Flutter

© 2026 AE Dev - Blog công nghệ, lập trình và chia sẻ kiến thức IT.

wpDiscuz
0
0
Would love your thoughts, please comment.x
()
x
| Reply