2009-06-15 11 views
6

tôi đang chèn một bản ghi vào một bảng SQL Server và sau đó chọn ID auto-increment như sau:Tại sao Máy chủ SQL sau chèn khóa bế tắc khi chạy trong một giao dịch?

(@p0 int,@p1 nvarchar(8))INSERT INTO [dbo].[Tag]([Some_Int], [Tag]) 
VALUES (@p0, @p1) 

SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value] 

(Điều này đã được tạo ra sử dụng LINQ-to-SQL). Đối với một số lý do khi tôi chạy mã này bên trong một giao dịch bằng cách sử dụng đối tượng TransactionScope với một mức cô lập Serializable, SQL Server ném một lỗi bế tắc. Tôi đã phân tích các sự kiện bế tắc graph và thấy rằng hai quá trình liên quan đến mỗi người đều chờ đợi mặt khác để thực hiện các hoạt động chuyển đổi, như tôi hiểu được những thông tin sau:

<resource-list> 
    <keylock hobtid="72057594101170176" dbid="5" objectname="foo.dbo.Tag" indexname="PK_Tag_1" id="lockb77cdc0" mode="RangeS-S" associatedObjectId="72057594101170176"> 
    <owner-list> 
    <owner id="processc9be40" mode="RangeS-S"/> 
    </owner-list> 
    <waiter-list> 
    <waiter id="processc9ae38" mode="RangeI-N" requestType="convert"/> 
    </waiter-list> 
    </keylock> 
    <keylock hobtid="72057594101170176" dbid="5" objectname="foo.dbo.Tag" indexname="PK_Tag_1" id="lockb77cdc0" mode="RangeS-S" associatedObjectId="72057594101170176"> 
    <owner-list> 
    <owner id="processc9ae38" mode="RangeS-S"/> 
    </owner-list> 
    <waiter-list> 
    <waiter id="processc9be40" mode="RangeI-N" requestType="convert"/> 
    </waiter-list> 
    </keylock> 
    </resource-list> 

sự hiểu biết của tôi là phạm vi giao dịch sẽ ngăn cản thứ hai quá trình thực hiện chèn cho đến khi người đầu tiên hoàn tất cả việc chèn và chọn danh tính. Tuy nhiên điều này dường như không đúng. Bất cứ ai có thể làm sáng tỏ một số cách tiếp cận tốt nhất để đạt được những gì tôi yêu cầu trong một cách an toàn thread?

- Cập nhật -

Chỉ cần lưu ý; Tôi chắc chắn rằng 99% kết nối không được chia sẻ giữa hai quy trình khi mỗi quá trình tạo một DataContext mới để giao tiếp với cơ sở dữ liệu.

- Cập nhật lần nữa -

Remus Rusanu chỉ ra rằng một số thông tin bỏ qua có liên quan đến vấn đề này, tôi đã cố gắng để đơn giản hóa các kịch bản dựa trên báo cáo bế tắc biểu đồ, nhưng tôi đã mở rộng giải thích đây. Trước khi tôi chèn, tôi thực hiện truy vấn tồn tại trên bảng được đề cập để xác định xem thẻ đã tồn tại hay chưa. Nếu tôi kết thúc giao dịch. Nếu không chèn nên đi trước và sau đó tôi thực hiện một bản cập nhật, không được hiển thị ở đây, trên một bảng có Some_Int làm khóa chính, mặc dù bản cập nhật hoàn toàn là giá trị được sửa đổi lần cuối. Nó cũng có thể là quan trọng mà bảng Tag có một chỉ số nhóm bao gồm cả các tự động inc ID và Some_Int. Tôi không nghĩ rằng phần thông tin cuối cùng này có liên quan như tôi đã thử thay đổi bảng để chỉ có trường tự động inc là chỉ mục khóa/nhóm chính không có kết quả.

Cảm ơn.

+0

Câu hỏi hay ho! Tôi muốn xem câu trả lời. – Chris

Trả lời

7

'Chuyển đổi' được đề cập là 'lock convert' from RangeS-S to RangeI-N, không liên quan đến chức năng 'CONVERT' theo bất kỳ cách nào. Thực tế là bạn có ổ khóa RangeS-S đã được đặt trên chỉ mục PK_Tag_1 cho biết bạn đang làm điều gì đó nhiều hơn chỉ là INSERT. Lần đầu tiên, giao dịch của bạn có thực hiện kiểm tra xem bản ghi mới có tồn tại trước khi thử chèn không?

+0

thực sự là nó ... – LaserJesus

+0

Tôi đã cập nhật câu hỏi để phản ánh tình hình hoàn toàn hơn – LaserJesus

+0

Tôi đã thay đổi mức cô lập thành ảnh chụp nhanh, điều này dường như đã làm giảm bớt tai họa bế tắc của tôi. Cảm ơn sự giúp đỡ của bạn :) – LaserJesus

-1

Bạn không cần giao dịch nào cả. Hàm scope_identity() sẽ trả về id được tạo lần cuối trong cùng một phạm vi, do đó, không có vấn đề gì nếu chèn khác được thực hiện trước khi bạn nhận được id, vì đó là trong một phạm vi khác.

+0

Phạm vi giao dịch là vì vậy tôi có thể cuộn các thay đổi trở lại nếu xảy ra sự cố ở nơi khác hoặc ít nhất là khi kiểm tra uni kết thúc. – LaserJesus

+0

@downvoter: Tại sao downvote? Nếu bạn không nói những gì bạn nghĩ là sai, nó không thể cải thiện câu trả lời bằng bất kỳ cách nào. – Guffa

0

Kiểm tra sự cách lyLevel, được sử dụng trong truy vấn của bạn. Lưu ý rằng TransactionScope sử dụng Serializable mức cô lập theo mặc định (http://msdn.microsoft.com/en-us/library/ms172152.aspx). Hãy thử thay đổi mức cách ly giao dịch của bạn thành Đã đọc Cam kết.