Race condition xảy ra khi nhiều request/process truy cập cùng một tài nguyên đồng thời và kết quả phụ thuộc vào thứ tự thực thi. Ví dụ kinh điển: hai request cùng đọc số dư 100, cùng trừ 30 rồi ghi lại → cả hai ghi 70 thay vì 40 (lost update). Dạng khác: check-then-act — kiểm tra "email chưa tồn tại" rồi insert, nhưng request khác chen vào giữa hai bước.
Các lớp phòng chống:
- Pessimistic lock: khóa hàng trước khi sửa (SELECT ... FOR UPDATE) — chắc chắn nhưng giảm mức song song.
- Optimistic lock: cột version; update kèm điều kiện WHERE version = ?, nếu 0 hàng bị ảnh hưởng thì retry.
- Atomic operation: dồn đọc-sửa-ghi vào một lệnh (UPDATE ... SET balance = balance - 30, Redis INCR) thay vì đọc ra rồi ghi lại.
- Transaction + isolation level phù hợp cho nhóm thao tác liên quan.
- Unique constraint ở DB: lưới an toàn cuối cho check-then-insert — DB tự chặn bản ghi trùng.
- Idempotency key cho request có thể bị retry (thanh toán, webhook).
Nguyên tắc: enforce ở tầng DB thay vì chỉ kiểm tra ở tầng ứng dụng — mọi kiểm tra ở app đều có khoảng hở thời gian.