2013-06-08 34 views
6

Trong mã Rails của tôi, tôi cần xác nhận rằng một hành động chỉ được phép nếu có nhiều hơn 1 bản ghi còn lại. Vì lý do này, tôi cần phải khóa cập nhật và sau đó thực hiện đọc. Mã đường ray của tôi trông giống như sau:Đường ray + MySQL + Giao dịch + Khóa, làm cách nào để ngăn chặn mở giao dịch khỏi mở khóa bảng?

PaymentProfile.transaction do 
    profiles = PaymentProfile.lock("LOCK IN SHARE MODE").where(user_id: xxx) 

    if profiles.count > 1 
    #allow 
    else 
    #do not allow 
    end 
end 

Về lý thuyết hoạt động tốt và khóa các hàng chính xác. HÃY BAO GIỜ, nếu một yêu cầu khác đi qua cùng một đường dẫn mã mở giao dịch sẽ xóa khóa tôi đã lấy ra trong quá trình khác, do đó sẽ đánh bại mục đích của khóa.

Từ các tài liệu MySQL:

Beginning a transaction also causes table locks acquired with LOCK TABLES to be released, as though you had executed UNLOCK TABLES. Beginning a transaction does not release a global read lock acquired with FLUSH TABLES WITH READ LOCK. 

Trả lời

2

Tôi sẽ giả định rằng một yêu cầu khác sẽ được xử lý bởi một tiến trình khác, hoặc ít nhất là với một kết nối (để MySQL) (xin lỗi tôi không biết gì về Ruby- trên đường ray).

Khóa được mua bởi một giao dịch cụ thể không thể được phát hành bởi giao dịch khác. Đây là mục đích của khóa. Như the manual đặt nó:

UNLOCK BẢNG bố một cách rõ ràng bất kỳ ổ khóa bảng tổ chức bởi phiên hiện tại

Nếu giả định của tôi là đúng, không có gì phải lo lắng cả. Nếu không, nếu hai yêu cầu có thể sử dụng cùng một kết nối cùng một lúc, có điều gì đó thực sự có nhiều kiến ​​trúc này ...

0

Có thể, trong trường hợp đó, bạn nên sử dụng một semaphore mutex (http://www.ruby-doc.org/core-2.0/Mutex.html) để tránh truy cập đồng thời tài nguyên được chia sẻ đó (trong trường hợp này, là bộ xử lý PaymentProfile của bạn). Bằng cách đó, bạn sẽ đảm bảo rằng hai quy trình đồng thời sẽ không truy cập khối mã được đồng bộ hóa cùng một lúc.

Hy vọng điều này sẽ giúp

Các vấn đề liên quan