0

Locking ActiveRecord

Vô tình đọc được bài viết về 1 đoạn code thanh toán trên facebook

Với trường hợp như trên, có thể tiềm ẩn xảy ra lỗi khi có muti-thread cùng chạy vào trong đoạn code trên Đơn giản hãy tưởng tượng một người dùng có id = 96 đang truy cập vào trang web để mua một số món hàng, chúng ta nhận vào tài khoản như thế này :


account1 = Account.find_by_user_id 96
account2 = Account.find_by_user_id 96

Sau khi chọn được món hàng yêu thích của mình với amount = $50, nhấp chuột kiểm tra và bắt đầu trả tiền cho món hàng đó. Trước khi thực hiện yêu cầu, đầu tiên chúng ta sẽ kiểm tra xem anh ta có đủ số tiền trong tài khoản của mình, và nếu anh ta thoả mãn điều kiện, chúng ta sau đó sẽ giảm số dư trong tài khoản của anh ấy một số tiền tương ứng với giá của mặt hàng đó. Tuy nhiên bằng cách nào đó, người dùng có thể mở nhiều tab và click đồng thời thanh toán cho vài món đồ. Mặc dù nó là rất hiếm, có thể có một cơ hội khi các yêu cầu trên tab đầu tiên và thứ hai đến máy chủ gần như cùng một thời điểm, và họ đều được xử lý bởi máy chủ đồng thời

Tôi chắc rằng bạn có thể thấy vấn đề bây giờ. Mặc dù sau khi mua món hàng đầu tiên, giả sử người sử dụng chỉ có $50 trong tài khoản của anh ta, và theo lý thuyết anh ta không thể mua nhiều hơn 1 món hàng có giá $50 . Nhưng ở đây, anh ta có thể mua cả nhiều món hàng vì nó vượt qua các kiểm tra điều kiện Bằng cách sử dụng Locking, chúng ta có thể ngăn chặn tình trạng tương tự. Khi Locking được đặt ra, họ sẽ không cho phép hai tiến trình đồng thời cập nhật các đối tượng trong cùng một thời điểm. Có 2 lọai lock trong rails:

  • Optimistic Locking
  • Pessimistic Locking

Optimistic Locking

Trong loại này, nhiều người dùng có thể truy cập cùng một đối tượng để đọc giá trị của nó, nhưng nếu hai người dùng thực hiện cập nhật thì sẽ phát sinh mâu thuẫn, chỉ có một người sử dụng sẽ thành công và một trong những người khác sẽ không được thực hiện.

account1 = Account.find_by_user_id 96
account2 = Account.find_by_user_id 96

account1.balance = "50"
account1.save

account2.balance = "60"
account2.save # Raises a ActiveRecord::StaleObjectError

Cơ chế của Optimistic Locking là tạo một field lock_version mà bạn muốn đặt khóa và Rails sẽ tự động kiểm tra trước khi cập nhật các đối tượng. Mỗi lần được cập nhật giá trị ấy sẽ tăng lên. Do đó nếu 2 yêu cầu cùng muốn được cập nhật, cái đầu tiên sẽ thành công còn cái thứ 2 sẽ trả lại ngoại lệ vì lock_version của nó đã được tăng lên. Nhiệm vụ của bạn là xử lý các ngoại lệ trả lại khi hoạt động cập nhật không thành công

Pessimistic Locking

Với loại locking này, chỉ có người dùng đầu tiên truy cập đến các đối tượng sẽ có thể cập nhật nó. Tất cả những người dùng khác sẽ bị loại khỏi kể cả việc đọc các đối tượng Rails sẽ thực hiện Pessimistic Locking bằng cách phát hành truy vấn đặc biệt trong cơ sở dữ liệu

account = Account.find_by_user_id 96

account.lock!
#no other users can read this account, they have to wait until the lock is released
account.save! 
#lock is released, other users can read this account

Kết Luận: Locking ActiveRecord có ích tùy thuộc vào yêu cầu. Hy vọng bài viết sẽ giúp ích cho các bạn hiểu thêm về locking trong rails


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí