C# 从数据库中选择并发任务
在数据库表中,我保存了一个任务列表。为了简单起见,假设任务是一个整数,并让表中有100个整数以递增的顺序排列。(增加顺序意味着如果有人正在处理任务N,则所有C# 从数据库中选择并发任务,c#,sql-server,database,concurrency,C#,Sql Server,Database,Concurrency,在数据库表中,我保存了一个任务列表。为了简单起见,假设任务是一个整数,并让表中有100个整数以递增的顺序排列。(增加顺序意味着如果有人正在处理任务N,则所有
getlock
read max_int
pick task
update tasksTable
releaselock
因为我只有大约10名员工,所以连载并不是什么大问题。如果我有1000个客户呢。如何使任务拾取并行化?您可以尝试使用锁定,但可以通过更新/选择来解决此问题:
BEGIN TRAN
UPDATE Task
SET clientId = MyClientId
WHERE [PrimaryKey] = (
SELECT TOP 1 [PrimaryKey]
FROM Tasks
WHERE clientId IS NULL
ORDER BY CreationDateTime)
SELECT * FROM Tasks
WHERE [PrimaryKey] = MyClientId
COMMIT TRAN
像这样的
或者可以使用OUPUT子句:
DECLARE @TaskId AS INT
UPDATE TOP(1) Task
SET clientId = MyClientId
OUTPUT Task.[PrimaryKey] INTO @TaskId
WHERE clientId IS NULL
ORDER BY CreationDateTime
SELECT @TaskId
(未对其进行测试)
来源:您可以尝试使用锁,但您可以通过更新/选择来解决此问题:
BEGIN TRAN
UPDATE Task
SET clientId = MyClientId
WHERE [PrimaryKey] = (
SELECT TOP 1 [PrimaryKey]
FROM Tasks
WHERE clientId IS NULL
ORDER BY CreationDateTime)
SELECT * FROM Tasks
WHERE [PrimaryKey] = MyClientId
COMMIT TRAN
像这样的
或者可以使用OUPUT子句:
DECLARE @TaskId AS INT
UPDATE TOP(1) Task
SET clientId = MyClientId
OUTPUT Task.[PrimaryKey] INTO @TaskId
WHERE clientId IS NULL
ORDER BY CreationDateTime
SELECT @TaskId
(未对其进行测试)
来源:假设两个表,一个用于未勾选的任务(WaitingTasks),一个用于勾选的“进行中”任务(WorkingTasks): 及 并行任务拾取可以这样完成:
INSERT INTO WorkingTasks (WaitingTaskID)
SELECT TOP 1 WaitingTaskID
FROM WaitingTasks
WHERE WaitingTaskID NOT IN (SELECT WaitingTaskID FROM WorkingTasks);
SELECT SCOPE_IDENTITY();
这将创建一个具有自己唯一ID的新“工作任务”,SCOPE_IDENTITY()将向您返回该唯一ID。假设有两个表,一个用于未点击的任务(WaitingTasks),一个用于点击的“进行中”任务(工作任务): 及 并行任务拾取可以这样完成:
INSERT INTO WorkingTasks (WaitingTaskID)
SELECT TOP 1 WaitingTaskID
FROM WaitingTasks
WHERE WaitingTaskID NOT IN (SELECT WaitingTaskID FROM WorkingTasks);
SELECT SCOPE_IDENTITY();
这将创建一个具有自己唯一ID的新“工作任务”,SCOPE_IDENTITY()将向您返回该唯一ID。不太了解您在这里所做的工作。在任务完成之前,是否锁定数据库表中的记录?如果是这样,我认为这不是一个好主意。相反,在任务数据库表中添加一列来提供任务的状态如何?如果已签出,则将其设置为true,否则将其设置为false。或者,您可以添加一列,指示签出对象(他的personID)。如果为空,则不会向任何人签出。注意:在这个解决方案中,您只有一个任务数据库表,而不是两个(一个单独的用于已完成任务的数据库表)。我认为这是一个更好的解决方案(更好的标准化) 仅向尚未分配的用户显示任务。如果他选择了一个,并且有人在他有机会点击更新按钮之前就击败他注册了该任务,你可以在更新时通知他已经太晚了。示例:此SQL中的“where”子句执行以下操作:“更新任务集personID=233421,其中personID==null”。如果更新返回时没有更新任何记录,则您知道发生了什么 我认为您的数据库/程序在支持数千个用户方面不会有任何问题,因为只有当多个用户在相同的几毫秒内更新任务表时,在第一次更新完成之前才会有轻微的延迟。即使如此,对于1000个用户,我怀疑会有超过10个左右的用户同时单击更新(几毫秒乘以10仍然不是很多时间) 另外,我认为您应该让数据库生成一个新的任务号,而不是通过task=max_int+1以编程方式进行。这样您就不必锁定表以确保在更新之前它不会更改。另请注意:如果每次更新都需要更新多个表,请设置一个事务。您不需要为一次表更新执行此操作
最后注意:处理更新的一个通用解决方案是向表中添加一个“版本”列(整数或长),并在每次有人更新记录时增加该列。然后,对于每个更新,查看版本号是否与上次读取时相同(SQL:update tasks set personID=233421,其中版本=4)。如果不一样,请通知用户。不太明白您在这里做什么。在任务完成之前,是否锁定数据库表中的记录?如果是这样,我认为这不是一个好主意。相反,在任务数据库表中添加一列来提供任务的状态如何?如果已签出,则将其设置为true,否则将其设置为false。或者,您可以添加一列,指示签出对象(他的personID)。如果为空,则不会向任何人签出。注意:在这个解决方案中,您只有一个任务数据库表,而不是两个(一个单独的用于已完成任务的数据库表)。我认为这是一个更好的解决方案(更好的标准化) 仅向尚未分配的用户显示任务。如果他选择了一个,并且有人在他有机会点击更新按钮之前就击败他注册了该任务,你可以在更新时通知他已经太晚了。示例:此SQL中的“where”子句执行以下操作:“更新任务集personID=233421,其中personID==null”。如果更新返回时没有更新任何记录,则您知道发生了什么 我认为您的数据库/程序在支持数千个用户方面不会有任何问题,因为只有当多个用户在相同的几毫秒内更新任务表时,在第一次更新完成之前才会有轻微的延迟。即使如此,对于1000个用户,我怀疑会有超过10个左右的用户同时单击更新(几毫秒乘以10仍然不是很多时间) 另外,我认为您应该让数据库生成一个新的任务号,而不是通过task=max_int+1以编程方式进行。这样您就不必锁定表以确保在更新之前它不会更改。另请注意:如果每次更新都需要更新多个表,请设置一个事务。您不需要为一次表更新执行此操作 最后一点注意:处理更新的一个通用解决方案是在表中添加一个“version”列(整数或长),并在每次有人更新时增加它