2012-02-13 34 views
5

Bạn sẽ giải quyết vấn đề tương tranh với mã sau đây như thế nào? Trong ví dụ này, chúng tôi muốn biết lý do tại sao xác thực người dùng không thành công. Vấn đề là mã này thực hiện hai cuộc gọi riêng biệt với cơ sở dữ liệu, nhưng chúng tôi muốn toàn bộ phương thức xảy ra bên trong một giao dịch khái niệm. Cụ thể, chúng tôi quan tâm đến số isolation. Chúng tôi không muốn đồng thời viết trong khi thực hiện phương pháp này để ảnh hưởng đến lần đọc của chúng tôi trước khi chúng tôi xác định lý do cho lỗi xác thực.Sự cố đồng thời với nhiều giao dịch cơ sở dữ liệu độc lập?

Một vài giải pháp cần lưu ý: Thread Locking, TransactionScopeOptimistic Locking. Tôi thực sự thích ý tưởng Khóa lạc quan, vì tôi nghĩ rằng xung đột có thể hiếm, nhưng không có gì được tích hợp vào .NET để làm điều này, đúng không?

Ngoài ra - đây có phải là điều gì đó thực sự lo ngại về trường hợp này không? Khi có các vấn đề tương tranh như thế này thì điều quan trọng cần xem xét và khi nào thì chúng? Những gì cần phải được xem xét trong việc thực hiện một giải pháp? Hiệu suất? Thời lượng của khóa? Khả năng xung đột sẽ xảy ra như thế nào?

Chỉnh sửa: Sau khi xem xét câu trả lời của Aristos, tôi nghĩ rằng những gì tôi thực sự sau là một số loại "snapshot" mức cách ly cho phương thức Xác thực.

public MembershipStatus Authenticate(string username, string password) 
    { 
     MembershipUser user = Membership.GetUser(username); 
     if (user == null) 
     { 
      // user did not exist as of Membership.GetUser 
      return MembershipStatus.InvalidUsername; 
     } 

     if (user.IsLockedOut) 
     { 
      // user was locked out as of Membership.GetUser 
      return MembershipStatus.AccountLockedOut; 
     } 

     if (Membership.ValidateUser(username, password)) 
     { 
      // user was valid as of Membership.ValidateUser 
      return MembershipStatus.Valid; 
     } 

     // user was not valid as of Membership.ValidateUser BUT we don't really 
     // know why because we don't have ISOLATION. The user's status may have changed 
     // between the call to Membership.GetUser and Membership.ValidateUser. 
     return MembershipStatus.InvalidPassword; 
    } 
+1

Tôi không chắc chắn rằng bạn thực sự cần phải lo lắng về việc bị cô lập ở đây. Cơ hội người dùng sẽ bị xóa hoặc bị khóa giữa cuộc gọi với 'GetUser' và' ValidateUser' là gì? Và hơn thế nữa, bạn không nên để lộ thông tin này cho người dùng. Nếu bạn hiển thị các thông báo khác nhau cho "mật khẩu sai" và "người dùng không tồn tại" và "tài khoản bị khóa", ai đó cố gắng hack trang web của bạn có thể tận dụng thông tin đó để có danh sách tên người dùng hợp lệ.Bạn không muốn điều đó, vì những tên người dùng đó có thể hữu ích trong việc khai thác một số lỗ hổng khác trong cơ sở hạ tầng của bạn. –

+0

+1 cho phản hồi. Tôi có thể sử dụng một ví dụ nghèo ở đây (mặc dù tôi đã có kế hoạch phân biệt giữa "thông tin đăng nhập không hợp lệ" và "tài khoản bị khóa" và có lẽ tôi cần suy nghĩ lại). Tôi không thích thực tế là dữ liệu có thể thay đổi bên dưới tôi! Đồng thời là khó! Điều gì sẽ xảy ra nếu tôi CẦN dữ liệu được nhất quán, bạn sẽ đề xuất điều gì? – Brandon

Trả lời

1

Dựa trên đọc sách của tôi herehere, nó có vẻ như một System.Transactions.TransactionScope gói toàn bộ phương pháp của bạn nên tự động tranh thủ các cuộc gọi cơ sở dữ liệu của bạn trong một giao dịch thông thường, kết quả trong giao dịch an toàn trên toàn bộ phạm vi giao dịch.

Bạn muốn làm điều gì đó như thế này:

public MembershipStatus Authenticate(string username, string password) 
{ 
    using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Snapshot })) 
    { 
    MembershipUser user = Membership.GetUser(username); 
     if (user == null) 
     { 
      // user did not exist as of Membership.GetUser 
      return MembershipStatus.InvalidUsername; 
     } 

     if (user.IsLockedOut) 
     { 
      // user was locked out as of Membership.GetUser 
      return MembershipStatus.AccountLockedOut; 
     } 

     if (Membership.ValidateUser(username, password)) 
     { 
      // user was valid as of Membership.ValidateUser 
      return MembershipStatus.Valid; 
     } 

     // user was not valid as of Membership.ValidateUser BUT we don't really 
     // know why because we don't have ISOLATION. The user's status may have changed 
     // between the call to Membership.GetUser and Membership.ValidateUser. 
     return MembershipStatus.InvalidPassword; 
    } 
} 
+0

+1 để dành thời gian trả lời. Tại sao tôi cần phải triển khai nhà cung cấp tư cách thành viên của riêng mình? Tôi không thể chỉ sử dụng lớp TransactionScope "trong đó các giao dịch được tự động quản lý bởi cơ sở hạ tầng"? – Brandon

+0

@Brandon xin lỗi mất quá nhiều thời gian để trả lời - Tôi muốn thực hiện một số nghiên cứu trước khi trả lời câu hỏi này. Tôi đã cập nhật câu trả lời của mình để phản ánh việc sử dụng TransactionScope. –

+0

cảm ơn phản hồi. Tôi đánh dấu đây là câu trả lời được chấp nhận, chủ yếu là cho bình luận đầu tiên của bạn cho câu hỏi của tôi (tôi có lẽ không nên làm điều này để bắt đầu và thậm chí nếu tôi muốn nó thực sự không phải là một vấn đề). – Brandon

1

tôi sẽ sử dụng mutex sử dụng tên như khóa parametre, vì vậy chỉ cùng một người dùng có thể có thể khóa ra cho một lúc. Điều này cho tôi là an toàn hơn cho một máy tính bởi vì với mutex tôi có thể nắm bắt tất cả các chủ đề có thể từ các hồ bơi khác nhau hoặc các cuộc gọi web.

public MembershipStatus AuthenticateLock(string username, string password) 
{ 
    if(string.IsNullOrEmpty(username)) 
     return MembershipStatus.InvalidUsername; 

    // TODO: Here you must check and clear for non valid characters on mutex name 
    using (var mutex = new Mutex (false, username)) 
    { 
     // possible lock and wait, more than 16 seconds and the user can go... 
     mutex.WaitOne (TimeSpan.FromSeconds(16), false); 

     // here I call your function anyway ! and what ever done... 
     // at least I get a result 
     return Authenticate(username, password) 
    } 
} 

Nhận xét khác: Cả hai Membership.ValidateUserMembership.GetUser gọi điện đến cơ sở dữ liệu.

Nhưng nếu bạn sử dụng phiên asp.net tiêu chuẩn cho các trang mà thực hiện cuộc gọi này và ảnh hưởng đến các thông số này, sau đó trang tất cả các khóa sẵn sàng một trong những người kia vì vậy tôi nghĩ rằng không có cơ hội để cần này cuộc gọi mutex. Vì khóa phiên là đủ để đồng bộ hóa và phần này. Tôi nhắc rằng phiên đang khóa trang từ đầu đến cuối cho tất cả người dùng.

Về khóa phiên: Replacing ASP.Net's session entirely

jQuery Ajax calls to web service seem to be synchronous

+0

+1 để dành thời gian trả lời câu hỏi này và cho thông tin Phiên. Vì vậy, bạn đang đề xuất khóa chuỗi. Khóa chủ đề cung cấp một loại cách ly "mềm", nhưng sẽ không hữu ích nếu bạn có nhiều quy trình (không phải luồng) đang cố gắng truy cập vào tài nguyên được chia sẻ. Tôi nghĩ rằng những gì tôi thực sự sau là một số loại "snapshot" mức cô lập cho phương pháp xác thực. – Brandon

+1

@Brandon Khóa mutex mà tôi sử dụng ở đây là rất hữu ích cho nhiều quy trình! Nhưng tôi nói rằng bạn không cần ngay cả điều này, nếu bạn sử dụng phiên trong tất cả các cuộc gọi của bạn đến chức năng này. Khóa phiên tất cả đã sẵn sàng các trang, vì vậy bạn không cần khóa thứ hai. – Aristos

+0

Thú vị! Tôi không biết rằng "Các mutex hệ thống được đặt tên được hiển thị trong toàn bộ hệ điều hành và có thể được sử dụng để đồng bộ hóa các hoạt động của các quá trình." Vì vậy, tôi đoán ranh giới là PC/OS, ví dụ: bạn không thể đồng bộ hóa các tiến trình với một mutex trên nhiều PC/OS? – Brandon

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