Thứ Hai, 9 tháng 9, 2013

Kỹ thuật kiểm tra bản ghi trùng lặp trước khi insert dữ liệu vào database ?


Đây là một kỹ thuật được sử dụng sai rất nhiều khi lập trình web application. Sai lầm nằm ở chỗ lập trình viên đã quên mất môi trường web application là môi trường multi-thread. Mỗi request của người dùng đến application sẽ được application xử lý trong một thread.

Giả sử bạn lập trình bằng struts action (1 hay 2 cũng được). Bạn viết đoạn code kiểm tra xem có yêu cầu insert có vi phạm một unique constraint nào không trước khi insert ? Bạn yên tâm là đoạn code bạn hoàn hảo. Đúng vậy nhưng chỉ trong môi trường single thread. Trong môi trường multi-thread thì sao ?

Giả sử có hai thread cùng muốn insert data, data của hai thread đều mới nhưng lại giống hệt nhau. Ví dụ cả hai cùng muốn insert user, username của cả hai đều giống nhau và đều chưa có trong database. Username đã được áp unique constraint.

Thread 1 check exists successfully -> Pause -> Thread 2 check exists successfully -> insert data -> Thread 2 insert successfully -> Thread 1 running -> insert data -> Thread 1 meet runtime exception. 

Nếu lập trình viên cẩu thả không áp unique constraint thì kết quả còn nghiêm trọng hơn: Lệnh insert của cả hai thread đều thành công dẫn đến dữ liệu trong bảng sẽ vi phạm business logic.

Đây là một trường hợp điển hình minh họa rằng check exists chẳng có tác dụng gì cả trong môi trường multi-thread

Vậy phương án giải quyết triệt để là gì ?
Áp unique constaint lên trường username.
Không cần check exists
Cho phép insert và catch exception ném ra từ database.
Xử lý exception đó và trả lại thông báo lỗi cho người dùng.

Lý do phương án đó thành công vì database có cơ chế lock table khi có một yêu cầu insert. 

Không có nhận xét nào:

Đăng nhận xét