2010-02-19 40 views
5

Đây là giải thích đơn giản về những gì tôi đang làm.
Tôi có một bảng có cột trạng thái. Nhiều phiên bản của ứng dụng sẽ kéo nội dung của hàng đầu tiên có trạng thái là NEW, cập nhật trạng thái thành WORKING và sau đó chuyển sang nội dung.
Thật dễ dàng để thực hiện điều này với hai cuộc gọi cơ sở dữ liệu; trước tiên là SELECT rồi đến số UPDATE. Nhưng tôi muốn làm tất cả trong một cuộc gọi để một thể hiện khác của ứng dụng không kéo cùng một hàng. Sắp xếp giống như một điều SELECT_AND_UPDATE.Tôi có thể chọn và cập nhật cùng một lúc không?

Quy trình được lưu trữ có phải là cách tốt nhất để đi không?

Trả lời

2

Âm thanh như một kịch bản xử lý hàng đợi, theo đó bạn chỉ muốn một quy trình để nhận một bản ghi nhất định.

Nếu đó là trường hợp, có một cái nhìn tại các câu trả lời tôi cung cấp trước ngày hôm nay trong đó mô tả làm thế nào để thực hiện logic này sử dụng một giao dịch kết hợp với UPDLOCK và READPAST gợi ý bảng: Row locks - manually using them

nhất gói lên trong sproc .

Tôi không chắc chắn đây là những gì bạn muốn làm, do đó tôi đã không bỏ phiếu để đóng là trùng lặp.

+0

Đây là những gì tôi cần. Cám ơn rất nhiều. –

1

Không hoàn toàn, nhưng bạn có thể SELECT ... WITH (UPDLOCK), sau đó UPDATE.. sau đó. Điều này là tốt như một hoạt động nguyên tử vì nó nói với cơ sở dữ liệu mà bạn sắp cập nhật những gì bạn đã chọn trước đó, vì vậy nó có thể khóa các hàng đó, ngăn ngừa va chạm với các máy khách khác. Theo Oracle và một số cơ sở dữ liệu khác (MySQL tôi nghĩ) cú pháp là SELECT ... FOR UPDATE.

Lưu ý: Tôi nghĩ bạn sẽ cần phải đảm bảo hai câu lệnh xảy ra trong một giao dịch để nó hoạt động.

+0

không nên ... VỚI UPDLOCK cho Sql Server.Ngoài ra, hãy cẩn thận vì gợi ý UPDLOCK có nghĩa là khóa được giữ với dữ liệu của bạn trong một giao dịch dài chạy có thể gây tranh chấp với các giao dịch khác –

+0

@Jeff: Vâng, nhưng từ mô tả của anh ta, đây là những gì anh ta muốn. Thật vậy, bạn cần phải cẩn thận với các giao dịch dài, nhưng đó là cách duy nhất tôi biết để có được một hành vi kiểu "đọc rồi viết" nguyên tử. – jkp

8

Bạn có thể sử dụng câu lệnh OUTPUT.

DECLARE @Table TABLE (ID INTEGER, Status VARCHAR(32)) 
INSERT INTO @Table VALUES (1, 'New') 
INSERT INTO @Table VALUES (2, 'New') 
INSERT INTO @Table VALUES (3, 'Working') 

UPDATE @Table 
SET  Status = 'Working' 
OUTPUT Inserted.* 
FROM @Table t1 
     INNER JOIN (
      SELECT TOP 1 ID 
      FROM @Table 
      WHERE Status = 'New' 
     ) t2 ON t2.ID = t1.ID 
+0

Lưu ý điều này yêu cầu SQL Server 2005 trở lên. – AakashM

+0

Tôi tin rằng tác giả muốn làm một số công việc phụ trong giao dịch, tuy nhiên, không có gì trong câu hỏi xác nhận nó. Một +1. – Quassnoi

+0

BTW, bạn không có 'JOIN' ở đây, một' CTE' sẽ đủ. – Quassnoi

1

Bạn nên làm ba việc ở đây:

  1. Khóa hàng bạn đang làm việc trên
  2. Hãy chắc chắn rằng điều này và chỉ hàng này bị khóa
  3. Đừng chờ đợi cho các khóa bản ghi: bỏ qua các bản ghi tiếp theo.

Để làm điều này, bạn chỉ cần phát hành này:

SELECT TOP 1 * 
FROM mytable (ROWLOCK, UPDLOCK, READPAST) 
WHERE status = 'NEW' 
ORDER BY 
     date 

UPDATE … 

trong một giao dịch.

1

Thủ tục được lưu trữ là cách thực hiện. Bạn cần phải xem xét các giao dịch. Sql server được sinh ra cho loại điều này.

1

Có, và có thể sử dụng gợi ý chặn hàng để giữ nó tách biệt với các chủ đề khác, ví dụ:

UPDATE 
Jobs WITH (ROWLOCK, UPDLOCK, READPAST) 
SET Status = 'WORKING' 
WHERE JobID = 
(SELECT Top 1 JobId FROM Jobs WHERE Status = 'NEW') 

CHỈNH SỬA: Hàng khóa sẽ tốt hơn theo đề xuất của Quassnoi, nhưng ý tưởng tương tự cũng áp dụng để thực hiện cập nhật trong một truy vấn.

+0

sẽ không phải là gợi ý đi trong CHỌN? –

+0

Tôi không nghĩ rằng nó tạo ra sự khác biệt vì chỉ có một hàng được chơi ở đây và nó nằm trong một câu lệnh. – Turnkey

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