2010-04-12 31 views
5

Tôi có một tình huống mà hai người có thể làm việc trên cùng một thứ tự (được lưu trữ trong cơ sở dữ liệu MS SQL) từ hai máy tính khác nhau. Để ngăn chặn mất dữ liệu trong trường hợp một người sẽ lưu bản sao của đơn đặt hàng trước, và sau đó một chút, lần thứ hai sẽ lưu bản sao của mình và ghi đè lên bản sao đầu tiên, tôi đã thêm séc vào trường lastSaved (datetime) trước tiết kiệm.MS SQL datetime vấn đề chính xác

Mã này sẽ gần như thế này:

private bool orderIsChangedByOtherUser(Order localOrderCopy) 
{ 
    // Look up fresh version of the order from the DB 
    Order databaseOrder = orderService.GetByOrderId(localOrderCopy.Id); 

    if (databaseOrder != null && 
     databaseOrder.LastSaved > localOrderCopy.LastSaved) 
    { 
     return true; 
    } 
    else 
    { 
     return false; 
    } 
} 

này làm việc cho hầu hết thời gian, nhưng tôi đã tìm thấy một lỗi nhỏ.

Nếu orderIsChangedByOtherUser lợi nhuận sai, bản sao cục bộ sẽ có nó lastSaved được cập nhật đến thời điểm hiện tại và sau đó được tiếp tục tồn cơ sở dữ liệu. Giá trị của lastSaved trong bản sao cục bộ và DB giờ đây sẽ giống nhau. Tuy nhiên, nếu orderIsChangedByOtherUser được chạy lại, đôi khi trả về đúng mặc dù không có người dùng nào khác đã thực hiện thay đổi đối với DB.

Khi gỡ lỗi trong Visual Studio, databaseOrder.LastSavedlocalOrderCopy.LastSaved dường như có giá trị như nhau, nhưng khi nhìn gần hơn họ một số lần khác nhau bởi một vài mili giây.

tôi thấy this article với một thông báo ngắn về độ chính xác millisecond cho datetime trong SQL:

vấn đề khác là SQL Server cửa hàng DATETIME với một độ chính xác của 3,33 mili giây (0. 00.333 giây).

Giải pháp tôi có thể nghĩ về vấn đề này, là so sánh hai thời gian biểu và xem xét chúng bằng nhau nếu chúng khác nhau ít hơn 10 mili giây.

Câu hỏi của tôi với bạn là: có cách nào tốt hơn/an toàn hơn để so sánh hai giá trị datetime trong MS SQL để xem chúng có phải là chính xác là không?

+0

Chỉ cần chỉ định: Tôi không có tùy chọn để thay đổi loại trường * lastSaved *, vì vậy tôi sẽ phải gắn bó với datetime. – Nailuj

Trả lời

4

Tôi biết bạn nói bạn không thể thay đổi kiểu, nhưng nếu điều này chỉ là để duy trì khả năng tương thích & bạn sử dụng 2008, bạn có thể thay đổi lĩnh vực lastSaved-DATETIME2 (đó là hoàn toàn tương thích với DATETIME) và sử dụng SYSDATETIME() cả hai đều có độ chính xác cao hơn nhiều.

+0

Tôi không biết datetime2. Máy chủ thử nghiệm của tôi ít nhất là chạy SQL Server 2008, do đó có thể thực sự là một tùy chọn. Chỉ cần có để đảm bảo rằng tất cả những người sử dụng hệ thống cũng được vào năm 2008 ... Cảm ơn :) – Nailuj

0

Bạn có thể sử dụng trường dấu thời gian để kiểm tra ngày chỉnh sửa cuối cùng thay vì trường ngày giờ? (Trong SQL 2008 này bây giờ là RowVersion)

+0

Có thể là một khả năng, nhưng tôi không có tùy chọn để thay đổi loại trường LastSaved. – Nailuj

+0

Bạn không cần phải làm như vậy. Thêm một trường bổ sung cho nó. Sau đó sửa đổi SP UPDATE để kiểm tra bởi cả PK và trường phiên bản hàng. Bạn sẽ nhận được 0 hàng bị ảnh hưởng nếu phiên bản hàng đã thay đổi sau đó. –

0

YOu phải đảm bảo các vạch thời gian của bạn sắp xếp - điều này chủ yếu là do có logic thích hợp ở phía C# để thực sự giảm độ chính xác dưới gốc trong DateTime đối tượng - về cơ bản làm cho suer bạn có ví dụ timestamps luôn luôn trong giây, không thấp hơn, trên tất cả các lớp.

Nếu bạn làm điều đó đúng cách, dấu thời gian trên tất cả các lớp sẽ được so sánh ngay lập tức.

2

Bạn có thể thêm trường sửa đổi số nguyên vào bảng đặt hàng của mình. Mỗi lần người dùng lưu thứ tự bạn tăng bản sửa đổi một lần. Sau đó, nó dễ dàng để kiểm tra xem ai đó đã thay đổi thứ tự hoặc nếu người dùng muốn lưu đơn đặt hàng là trên phiên bản mới nhất.

1

Trong khi bạn đang ở trong SQL 2005 và trước khi vấn đề về độ chính xác sẽ luôn ở đó, không bao giờ chính xác hơn 1/300th của giây, hoặc 3.33ms.

Bất kể sự thiếu chính xác bạn đang lập trình một tình trạng thiếu sót mà cả hai người dùng vẫn có thể viết vào cơ sở dữ liệu trong thành công nhanh chóng nhưng cả hai đều được coi là thành công. Việc thiếu độ chính xác làm tăng cơ hội xảy ra, miễn là kiểm tra và ghi tiếp theo xảy ra trong cùng 3-4 ms.

Bất kỳ nỗ lực nào để kiểm tra theo sau là chữ viết bị vấn đề này và bạn phải chấp nhận hậu quả của khóa lạc quan, thay đổi khóa thành pessemistic hoặc thực hiện một số loại chiến lược kiểu semaphore để xử lý khóa đúng cách.

+0

Tôi nhận thức được logic có thể thiếu sót, nhưng cũng như với nhiều hệ thống cũ, nó chỉ là thứ mà người ta phải sống. Tôi đã có một hy vọng nhỏ có thể có một cách xung quanh, nhưng tôi nghĩ rằng chúng ta có thể sống với độ chính xác 0.33ms. – Nailuj

0

Có một cách khác để thực hiện điều này có khả năng.

Thay vì truyền trong "Lần lưu cuối cùng" từ máy cục bộ, hãy sửa đổi thủ tục lưu sẵn UPDATE. Gán LastSaved = getdate() Sau đó trả về giá trị của LastSaved (và bất kỳ kết quả nào khác, chẳng hạn như ID), và cập nhật LastSaved time tại máy khách với kết quả đó.

Có hai lợi thế rõ ràng cho điều này. Một là độ chính xác của DateTime được giữ nguyên. Cách khác là ngày giờ phù hợp với máy chủ, thay vì phải chịu bất kỳ độ trễ mạng nào và các sự cố trôi dạt đồng hồ cục bộ.

Chúng tôi thường sử dụng SP được tạo tự động cho các hoạt động CRUD và các bảng thường chạy các cặp "Created/LastUpdated" và "CreatedBy/LastUpdatedBy" trong đó ngày được đặt trên máy chủ và các giá trị "By" được chuyển vào, và nếu NULL được đặt thành System_User

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