SQL 服务器锁定 Rows/Table
SQL Server Locking Rows/Table
我有一个必须执行以下操作的存储过程:
- Select 来自 table
的未标记行
- 标记所选行
- 向客户端发送 500 行
我有四个客户端,每个客户端每分钟 运行,并调用此存储过程。
每个客户端只能接收他们自己的 500 行。两个客户永远不应该得到同一行。
有时候会出现两个客户端走同一条线,我想解决这个问题。
(我的想法是将代码重写为只有一个有输出的更新语句)
对于这种情况,哪种方法最好?我需要配置隔离级别吗?
这是当前代码示例:
SET XACT_ABORT ON
BEGIN TRANSACTION
DECLARE @IDs TABLE (ID INT) -- declaring table variable
INSERT INTO @IDs -- insert unflagged IDs (data) into table variable with update lock
SELECT TOP 500 p.[ID]
FROM [Core].[Poruka] p WITH (UPDLOCK)
JOIN Core.vwKorisnickiRacunOmogucenoSlanje vk
ON p.KorisnickiRacunSifra = vk.KorisnickiRacunSifra
WHERE
(p.Zauzeto = 0 OR p.Zauzeto IS NULL)
AND vk.OmogucenoSlanjePoruka = 1
ORDER BY
vk.Prioritet
UPDATE p -- update table to flagged
SET Zauzeto = 1
FROM Core.Poruka p
JOIN @IDs tmp ON tmp.ID = p.ID
SELECT * -- select data to client
FROM [Core].[Poruka] p
WHERE p.ID IN (SELECT ID
FROM @IDs)
COMMIT
这里不需要交易。
只需使用OUTPUT
将更改的行输出到客户端
UPDATE p
SET Zauzeto = 1 -- update table to flagged
OUTPUT inserted.* -- output to client
FROM (
SELECT TOP (500)
p.*
FROM [Core].[Poruka] p
JOIN Core.vwKorisnickiRacunOmogucenoSlanje vk
ON p.KorisnickiRacunSifra = vk.KorisnickiRacunSifra
WHERE
(p.Zauzeto = 0 OR p.Zauzeto IS NULL)
AND vk.OmogucenoSlanjePoruka = 1
ORDER BY
vk.Prioritet
) p;
您确实应该将此联接作为 EXISTS
,以避免从联接返回重复的行。
UPDATE p
SET Zauzeto = 1 -- update table to flagged
OUTPUT inserted.* -- output to client
FROM (
SELECT TOP (500)
p.*
FROM [Core].[Poruka] p
WHERE
(p.Zauzeto = 0 OR p.Zauzeto IS NULL)
AND EXISTS (SELECT 1
FROM Core.vwKorisnickiRacunOmogucenoSlanje vk
WHERE
p.KorisnickiRacunSifra = vk.KorisnickiRacunSifra --join condition
AND vk.OmogucenoSlanjePoruka = 1
)
ORDER BY
vk.Prioritet
) p;
SERIALIZABLE
(又名 HOLDLOCK
)隔离级别在这里是明智的。
我有一个必须执行以下操作的存储过程:
- Select 来自 table 的未标记行
- 标记所选行
- 向客户端发送 500 行
我有四个客户端,每个客户端每分钟 运行,并调用此存储过程。
每个客户端只能接收他们自己的 500 行。两个客户永远不应该得到同一行。
有时候会出现两个客户端走同一条线,我想解决这个问题。
(我的想法是将代码重写为只有一个有输出的更新语句)
对于这种情况,哪种方法最好?我需要配置隔离级别吗?
这是当前代码示例:
SET XACT_ABORT ON
BEGIN TRANSACTION
DECLARE @IDs TABLE (ID INT) -- declaring table variable
INSERT INTO @IDs -- insert unflagged IDs (data) into table variable with update lock
SELECT TOP 500 p.[ID]
FROM [Core].[Poruka] p WITH (UPDLOCK)
JOIN Core.vwKorisnickiRacunOmogucenoSlanje vk
ON p.KorisnickiRacunSifra = vk.KorisnickiRacunSifra
WHERE
(p.Zauzeto = 0 OR p.Zauzeto IS NULL)
AND vk.OmogucenoSlanjePoruka = 1
ORDER BY
vk.Prioritet
UPDATE p -- update table to flagged
SET Zauzeto = 1
FROM Core.Poruka p
JOIN @IDs tmp ON tmp.ID = p.ID
SELECT * -- select data to client
FROM [Core].[Poruka] p
WHERE p.ID IN (SELECT ID
FROM @IDs)
COMMIT
这里不需要交易。
只需使用OUTPUT
将更改的行输出到客户端
UPDATE p
SET Zauzeto = 1 -- update table to flagged
OUTPUT inserted.* -- output to client
FROM (
SELECT TOP (500)
p.*
FROM [Core].[Poruka] p
JOIN Core.vwKorisnickiRacunOmogucenoSlanje vk
ON p.KorisnickiRacunSifra = vk.KorisnickiRacunSifra
WHERE
(p.Zauzeto = 0 OR p.Zauzeto IS NULL)
AND vk.OmogucenoSlanjePoruka = 1
ORDER BY
vk.Prioritet
) p;
您确实应该将此联接作为 EXISTS
,以避免从联接返回重复的行。
UPDATE p
SET Zauzeto = 1 -- update table to flagged
OUTPUT inserted.* -- output to client
FROM (
SELECT TOP (500)
p.*
FROM [Core].[Poruka] p
WHERE
(p.Zauzeto = 0 OR p.Zauzeto IS NULL)
AND EXISTS (SELECT 1
FROM Core.vwKorisnickiRacunOmogucenoSlanje vk
WHERE
p.KorisnickiRacunSifra = vk.KorisnickiRacunSifra --join condition
AND vk.OmogucenoSlanjePoruka = 1
)
ORDER BY
vk.Prioritet
) p;
SERIALIZABLE
(又名 HOLDLOCK
)隔离级别在这里是明智的。