2009-03-30 29 views
5

Tôi có bảng dữ liệu kế thừa trong SQL Server 2005 có PK không có nhận dạng/tự động và không có quyền thực hiện.Cách tránh tình trạng chạy cơ sở dữ liệu khi tăng PK theo cách thủ công của hàng mới

Kết quả là, tôi buộc phải tạo bản ghi mới trong ASP.NET theo cách thủ công thông qua bảng ole "SELECT MAX (id) + 1 FROM" - trước khi chèn kỹ thuật.

Rõ ràng điều này tạo ra một điều kiện chủng tộc trên ID trong trường hợp chèn đồng thời.

Cách tốt nhất để giải quyết một cách duyên dáng sự kiện xảy ra xung đột cuộc đua là gì? Tôi đang tìm các ý tưởng VB.NET hoặc C# code dọc theo các dòng phát hiện một va chạm và sau đó lại cố gắng chèn không thành công bằng cách nhận được một tối đa (id) + 1. Điều này có thể được thực hiện?

Suy nghĩ? Bình luận? Sự khôn ngoan?

Cảm ơn bạn!

LƯU Ý: Điều gì xảy ra nếu tôi không thể thay đổi cơ sở dữ liệu theo bất kỳ cách nào?

Trả lời

4

Không thể thay đổi giản đồ cơ sở dữ liệu là khắc nghiệt.

Nếu bạn chèn PK hiện có vào bảng, bạn sẽ nhận được SqlException với thông báo cho biết vi phạm ràng buộc PK. Nắm bắt ngoại lệ này và thử lại thêm vài lần cho đến khi bạn thành công. Nếu bạn thấy rằng tỷ lệ va chạm quá cao, bạn có thể thử max(id) + <small-random-int> thay vì max(id) + 1. Lưu ý rằng với cách tiếp cận này, id của bạn sẽ có khoảng trống và không gian id sẽ cạn kiệt sớm hơn.

Một cách tiếp cận khác có thể là mô phỏng tự động phát sinh id bên ngoài cơ sở dữ liệu. Ví dụ: tạo một số nguyên tĩnh, Interlocked.Increment mỗi lần bạn cần id tiếp theo và sử dụng giá trị trả về. Phần khó khăn là khởi tạo bộ đếm tĩnh này với giá trị tốt. Tôi sẽ làm điều đó với Interlocked.CompareExchange:

class Autoincrement { 
    static int id = -1; 
    public static int NextId() { 
    if (id == -1) { 
     // not initialized - initialize 
     int lastId = <select max(id) from db> 
     Interlocked.CompareExchange(id, -1, lastId); 
    } 
    // get next id atomically 
    return Interlocked.Increment(id); 
    } 
} 

Rõ ràng là tác phẩm thứ hai chỉ khi tất cả id chèn thu được qua Autoincrement.NextId của quá trình duy nhất.

+0

Chỉ cần những gì tôi cần cảm ơn !!! –

6

Tạo bảng phụ với cột nhận dạng. Trong một giao dịch chèn vào bảng aux, lấy giá trị và sử dụng nó để chèn vào bảng kế thừa của bạn. Tại thời điểm này, bạn thậm chí có thể xóa hàng được chèn vào bảng aux, điểm này chỉ là sử dụng nó như là một nguồn của các giá trị tăng dần.

+0

Thực hiện đơn giản hơn nhiều, +1 –

+0

Rất thông minh, cảm ơn! Thật không may tôi không có cách nào để thay đổi cơ sở dữ liệu. Nó bị đóng băng. –

+0

Thêm nó làm cơ sở dữ liệu thứ hai, được liên kết - hoặc sử dụng một tệp XML cục bộ cho mã để đạt được điều tương tự. –

1

Giải pháp tốt nhất là thay đổi cơ sở dữ liệu. Bạn không thể thay đổi cột thành cột nhận dạng, nhưng bạn sẽ có thể đảm bảo có một ràng buộc duy nhất trên cột và thêm một cột nhận dạng mới giống với PK hiện có của bạn. Sau đó, hãy sử dụng cột mới thay thế hoặc sử dụng trình kích hoạt để làm cho cột cũ phản chiếu mới hoặc cả hai.

3

Điều quan trọng là làm điều đó trong một tuyên bố hoặc một giao dịch.

Bạn có thể làm điều này không?

INSERT (PKcol, col2, col3, ...) 
SELECT (SELECT MAX(id) + 1 FROM table WITH (HOLDLOCK, UPDLOCK)), @val2, @val3, ... 

Nếu không có thử nghiệm, điều này sẽ có thể làm việc quá:

INSERT (PKcol, col2, col3, ...) 
VALUES ((SELECT MAX(id) + 1 FROM table WITH (HOLDLOCK, UPDLOCK)), @val2, @val3, ...) 

If you can not, một cách khác là để làm điều đó trong một cò.

  1. Trigger là một phần của giao dịch INSERT
  2. Sử dụng HOLDLOCK, UPDLOCK cho MAX. Này giữ khóa hàng cho đến khi cam kết
  3. Hàng được cập nhật bị khóa trong suốt thời gian

Một chèn thứ hai sẽ đợi cho đến khi Hoàn thành đầu tiên. Nhược điểm là bạn đang thay đổi khóa chính.

Bảng phụ trợ cần phải là một phần của giao dịch.

Hoặc thay đổi giản đồ như được đề xuất ...

+0

Tôi đã thử một chèn lồng nhau và nó nói với tôi rằng tôi không thể chèn lồng nhau. Tôi cũng không có quyền thay đổi cơ sở dữ liệu theo bất kỳ cách nào khác với SQL Updates/Inserts. –

+0

Giao dịch phía khách hàng được cho phép trong mã máy khách của bạn – gbn

2

Điều gì về việc chạy toàn bộ hàng loạt (chọn cho id và chèn) trong giao dịch tuần tự?

Điều đó sẽ giúp bạn xung quanh cần thực hiện thay đổi trong cơ sở dữ liệu.

3

Lưu ý: Tất cả những gì bạn cần là nguồn của các số nguyên ngày càng tăng. Nó không phải đến từ cùng một cơ sở dữ liệu, hoặc thậm chí từ một cơ sở dữ liệu nào cả.

Cá nhân, tôi sẽ sử dụng SQL Express vì nó miễn phí và dễ dàng.

Nếu bạn có một máy chủ web đơn lẻ: Tạo cơ sở dữ liệu SQL Express trên máy chủ web với một bảng [id] với một trường tự động phát [new_id]. Chèn một bản ghi vào bảng [id] này, lấy [new_id] và chuyển nó vào lớp cơ sở dữ liệu của bạn làm PK của bảng đang được đề cập đến.

Nếu bạn có nhiều máy chủ web: Đó là một nỗi đau để thiết lập, nhưng bạn có thể sử dụng các thủ thuật tương tự bằng cách thiết lập phù hợp hạt/increment (tức increment = 3, và hạt giống = 1/2/3 cho ba web máy chủ).

1

Mối quan tâm chính có đồng thời không? Ý tôi là, sẽ có nhiều trường hợp ứng dụng của bạn (hoặc, Thiên Chúa cấm, các ứng dụng khác ngoài tầm kiểm soát của bạn) đang thực hiện chèn đồng thời?

Nếu không, bạn có thể quản lý chèn thông qua mô-đun trung tâm, đồng bộ hóa trong ứng dụng của mình và tránh hoàn toàn các điều kiện chủng tộc.

Nếu có, tốt ... như Joel đã nói, hãy thay đổi cơ sở dữ liệu. Tôi biết bạn không thể, nhưng vấn đề là cũ như những ngọn đồi, và nó đã được giải quyết tốt - ở cấp độ cơ sở dữ liệu. Nếu bạn muốn sửa chữa nó cho mình, bạn sẽ chỉ phải lặp lại (chèn, kiểm tra va chạm, xóa) hơn và hơn và hơn nữa. Vấn đề cơ bản là bạn không thể thực hiện một giao dịch (tôi không có nghĩa là trong SQL "GIAO DỊCH" nghĩa, nhưng trong ý nghĩa lý thuyết dữ liệu lớn hơn) nếu bạn không có sự hỗ trợ từ cơ sở dữ liệu. Điều duy nhất tôi nghĩ là nếu bạn ít nhất có quyền kiểm soát ai có quyền truy cập vào cơ sở dữ liệu (ví dụ, chỉ các ứng dụng "được ủy quyền" mới được viết hoặc phê duyệt), bạn có thể thực hiện một mutex bên-dải các loại, nơi một "thanh nói" được chia sẻ bởi tất cả các ứng dụng và quyền sở hữu của mutex là bắt buộc để thực hiện chèn. Tuy nhiên, đó sẽ là quả bóng lông của chính nó, vì bạn phải tìm ra chính sách cho khách hàng đã chết, nơi nó được lưu trữ, các vấn đề về cấu hình, v.v. thiết lập toàn bộ ống.

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