IDENTITY_INSERT ảnh hưởng đến đồng thời như thế nào?


11

Tôi đang cố gắng giúp khách hàng với tiện ích bổ sung SAP của bên thứ 3 có trục trặc khi đăng bài và đã hết hỗ trợ.

Trong một số trường hợp nhất định, nó lưu trữ và đăng không đầy đủ từ bảng xếp hàng đăng lên bảng lưu trữ đăng. Tôi cần chuyển các kết quả lưu trữ này trở lại hàng đợi.

ID hàng đợi là một cột danh tính và tôi muốn giữ nó như cũ.

Câu hỏi là, nếu tôi tắt / insert / id_insert, tôi có thể mong đợi gì về sự tương tranh với các quy trình tạo ra các mục hàng đợi và hy vọng cột nhận dạng sẽ được tạo tự động?

Bất kỳ con trỏ về cách tốt nhất để chứng minh hành vi như vậy cũng sẽ được đánh giá rất cao.

Câu trả lời:


8

Tự thiết lập IDENTITY_INSERT ONkhông loại bỏ đồng thời - điều này không đặt bất kỳ khóa độc quyền nào trên bàn, chỉ có khóa ổn định lược đồ ngắn (Sch-S).

Vì vậy, về mặt lý thuyết có thể xảy ra, theo hành vi mặc định, bạn có thể làm điều này trong phiên 1:

BEGIN TRANSACTION;

-- 1
SET IDENTITY_INSERT dbo.tablename ON;

-- 2
INSERT dbo.tablename(id, etc) VALUES(100, 'foo'); -- next identity is now 101

-- 3
INSERT dbo.tablename(id, etc) VALUES(101, 'foo'); -- next identity is now 102

-- 4
SET IDENTITY_INSERT dbo.tablename OFF;

COMMIT TRANSACTION;

Trong một phiên khác, bạn có thể chèn các hàng vào bảng tại các điểm 1, 2, 3 hoặc 4. Điều này có vẻ như là một điều tốt, ngoại trừ điều xảy ra đối với bất kỳ thao tác chèn nào xảy ra giữa 2 và 3, là giá trị được tạo tự động được kích hoạt bởi một phiên khác dựa trên kết quả của câu lệnh 2 - vì vậy nó sẽ tạo ra 101 và sau đó câu lệnh 3 sẽ thất bại với vi phạm khóa chính. Điều này khá đơn giản để thiết lập và tự kiểm tra với một số WAITFORs:

-- session 1
-- DROP TABLE dbo.what;
CREATE TABLE dbo.what(id INT IDENTITY PRIMARY KEY);
GO
BEGIN TRANSACTION;

SET IDENTITY_INSERT dbo.what ON;

INSERT dbo.what(id) VALUES(32);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(33);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(34);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(35);
WAITFOR DELAY '00:00:05';
INSERT dbo.what(id) VALUES(36);

SET IDENTITY_INSERT dbo.what OFF;

COMMIT TRANSACTION;

Khi đợt đó đã bắt đầu, hãy bắt đầu đợt này trong một cửa sổ khác:

-- session 2
INSERT dbo.what DEFAULT VALUES;
WAITFOR DELAY '00:00:01';
GO 20

Phần 2 chỉ nên chèn các giá trị từ 1-20, phải không? Ngoại trừ điều đó bởi vì danh tính cơ bản đã được cập nhật bằng cách chèn thủ công phiên 1, tại một số điểm phiên 2 sẽ chọn nơi phiên 1 rời đi và chèn 32, hoặc 33 hoặc 34, v.v. Nó sẽ được phép làm điều này, nhưng sau đó phiên 1 sẽ thất bại trong lần chèn tiếp theo với vi phạm PK (cái nào thắng có thể chỉ là vấn đề thời gian).

Một cách để khắc phục điều này là gọi một TABLOCKlần chèn đầu tiên:

INSERT dbo.what WITH (TABLOCK) (id) VALUES(32);

Điều này sẽ chặn bất kỳ người dùng nào khác đang cố gắng chèn (hoặc làm bất cứ điều gì, thực sự) với bảng này cho đến khi bạn hoàn thành việc di chuyển các hàng lưu trữ đó trở lại. Điều này đồng thời, chắc chắn, nhưng đây là cách bạn muốn chặn để làm việc. Và hy vọng rằng đây không phải là điều gì đó xảy ra với tốc độ thường xuyên như vậy khi bạn chặn người khác mọi lúc.

Một vài cách giải quyết khác:

  • ngừng quan tâm về IDENTITYgiá trị tạo ra. Ai quan tâm? Sử dụng một UNIQUEIDENTIFIER(có thể được tạo trong một bảng riêng với IDENTITYmột thay thế) nếu giá trị ban đầu là rất quan trọng.
  • thay đổi quy trình lưu trữ để sử dụng "xóa mềm" trong đó một cái gì đó được đánh dấu là lưu trữ ban đầu và việc lưu trữ sẽ không được thực hiện vĩnh viễn cho đến một ngày sau đó. Sau đó, bất cứ quy trình nào đang cố gắng di chuyển chúng trở lại có thể chỉ cần thực hiện cập nhật trực tiếp và sửa cờ xóa mềm.

Cảm ơn bạn đã giải thích của bạn. Tôi đang viết một tiện ích độc lập để hỗ trợ cho một sản phẩm không hỗ trợ tạo ra các trường nhận dạng này. Tôi không kiểm soát cách nó hoạt động.
Ẩn dụ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.