[Laravel] xử lý dữ liệu cùng một thời điểm
Mình có 1 hàm rut tiền khi trong tài khoản có tiền như này ( hàm ruttien) Người A tiền hành rút tiền.
function rutien(Resquest $r){
$a = NhanVien::where('id',$r->ID)->first();
$luong = $a->luong;
if($luong>0){
$daily->decrement('luong',$luong);
}
Nhưng cùng tại thời điểm đó thì người B, tiến hành hàm gửi tiền cho người A
function tangdiem( Resquest $r){
$b = NhanVien::where('id',$r->id)->first();
$sotien = 100;
$b->increment('luong',$sotien);
}
Lỗi của mình gặp phải là nếu A và B làm 2 thời gian lệch nhau thì ok, ngon lành không vấn đề gì, nhưng nếu cả hai cùng làm 1 thời điểm thì nó gặp phải lỗi hieur sai vấn đề, có nghĩa hàm rút tiền nó sẽ trừ nhiều hơn số tiền hiện có, làm cho số tiền của người A sau khi rút sẽ bị âm xuống.
Không hiểu mình bị sai chỗ nào mà gây ra chuyện này nhỉ, và có thể cho mình phương án xử lý . Thanks All.
5 CÂU TRẢ LỜI
Cái hàm so sánh kia thì ăn thua gì thím.
ví dụ số dư là 20k, 2 lệnh rút tiền cùng lúc thì phép so sánh >0 đều pass thôi
Làm cho cái hàm rút tiền đó chạy tuần tự (lock chỉ có 1 process chạy hàm này vào 1 thời điểm: cho vào queue rồi dùng 1 chạy chẳng hạn)
Mình hiểu ý bạn, nhưng có thể nói rõ hơn làm sao để biết cái nào đang chạy , để lock 1 cái chạy 1 cái .
@tinhtn89
Bạn thử đối ứng nó bằng queue nhé.
Tham khảo doc: https://laravel.com/docs/8.x/queues#introduction
Thay vì request rút tiền đến, bạn sẽ xử lý cho phép rút tiền ngay.
Thì bạn dispatch 1 lệnh rút tiền vào trong queue.
Tương tự với hàm gửi tiền cũng thế.
Queue giúp bạn đảm bảo được, mỗi thời điểm chỉ có 1 job rút tiền hay gửi tiền đc chạy.
Tiện thể bạn đặt tên hàm là tăng điểm à tangdiem
Cố gắng đặt lên dễ hiểu xíu nữa nhé.
Cảm ơn bạn, Mình viết tên hàm đó cho ae dễ hiểu thôi, tangdiem = tặng điểm Về cơ chế thì mình hiểu nhưng vẫn chưa biết cách viết như nào?
@tinhtn89
Bạn cứ lấy hướng dẫn gửi mail này làm ví dụ này.
https://rathorji.in/p/laravel_76_queue_tutorial_laravel_76_send_mail_with_queue_example
Thì bài toán trên của bạn cũng tương tự như vậy.
Nói queue sang miệng thế thôi, thực ra nó tạo trong db của bạn thêm 1 bảng, để đăng ký các job vào đó.
Sau đó cứ xử lý xong thì nó xóa đi.
Rồi tìm tới record tiếp theo để xử lý.
Theo mình bạn nên tìm hiểu thêm về transaction db và queue. giả sử trong trường hợp hết điện ở cái đoạn trừ tiền thì sao
Bạn tìm hiểu thằng này thử xem https://laravel.com/docs/8.x/queries#pessimistic-locking Ý tưởng là lock bản ghi lại, cho đến khi process khác xử lý xong
- đây là bài toán transaction nên dùng các database có cơ chế lock khi update/insert, ví dụ như mysql
- sử dụng cơ chế lock database để xử lí, bạn tham khảo bài này xem: https://viblo.asia/p/mysql-table-locking-yMnKMjjaZ7P