.net core 数据库查询不涉及事务
我有一段代码,用来一次一个地从数据库中提取项目。每次get时,它都会更新行的状态,以指示已检索该行,从而不会多次检索同一行 下面的代码是从为Web API提供服务的后端服务运行的。有时,当多个请求传入时,它将返回具有相同ID的同一行任务 我的印象是,有一个事务围绕着它,这意味着其中一个运行的更新将阻止第二个查询返回该行 任何帮助都将不胜感激.net core 数据库查询不涉及事务,.net-core,dapper,.net Core,Dapper,我有一段代码,用来一次一个地从数据库中提取项目。每次get时,它都会更新行的状态,以指示已检索该行,从而不会多次检索同一行 下面的代码是从为Web API提供服务的后端服务运行的。有时,当多个请求传入时,它将返回具有相同ID的同一行任务 我的印象是,有一个事务围绕着它,这意味着其中一个运行的更新将阻止第二个查询返回该行 任何帮助都将不胜感激 public async Task<TaskDetail> GetTask() { using (var db = new SqlCon
public async Task<TaskDetail> GetTask()
{
using (var db = new SqlConnection(""))
{
using (var tran = db.BeginTransaction())
{
try
{
var sql = $@"
SELECT TOP 1 * FROM
(SELECT TOP 150 t.*
FROM Task t
INNER JOIN TaskStatus ts ON t.Id = ts.TaskId AND ts.Status = @taskStatus) t
ORDER BY NEWID();";
var chosen = await db
.QuerySingleOrDefaultAsync<TaskDetail>(
sql,
param: new
{
taskStatus = TaskStatusEnum.Ready
},
transaction: tran
);
if (chosen == null)
{
throw new InvalidOperationException();
}
var expiry = await db.ExecuteAsync("UPDATE TaskStatus SET Status = @status WHERE TaskId = @taskId", new {status = TaskStatusEnum.Done, taskId = chosen.TaskId}, tran);
tran.Commit();
return chosen;
}
catch
{
tran.Rollback();
throw;
}
}
}
}
一些错误的配置可能是原因 1-检查SQL Server隔离级别,小心脏读。 2-确保正确处理web API中的错误,因为事务错误没有正确显示。
3-请从代码中删除t-sql:选择查询不会阻止来自其他事务的行数据,不同事务中的两个选择将同时执行。您可以尝试在行上设置会话id,然后选择它 编辑:希望此帮助,当执行更新时,它应该阻止其他事务的行
public async Task<TaskDetail> GetTask()
{
using (var db = new SqlConnection(""))
{
using (var tran = db.BeginTransaction())
{
try
{
var mySessionId = Guid.NewGuid();
var sql = $@"
UPDATE TaskStatus SET Status = @status, SessionId = @mySessionId WHERE TaskId in
(SELECT TOP 1
t.Id
FROM Task t
INNER JOIN TaskStatus ts ON t.Id = ts.TaskId AND ts.Status = @taskStatus ORDER BY NEWID());";
await db
.QuerySingleOrDefaultAsync<TaskDetail>(
sql,
param: new
{
taskStatus = TaskStatusEnum.Ready
status = TaskStatusEnum.InProgress,
mySessionId = mySessionId
},
transaction: tran
);
var sql = $@"
SELECT TOP 150 t.*
FROM Task t
INNER JOIN TaskStatus ts ON t.Id = ts.TaskId AND ts.Status = @taskStatus
WHERE ts.SessionId = @mySessionId;";
var chosen = await db
.QuerySingleOrDefaultAsync<TaskDetail>(
sql,
param: new
{
taskStatus = TaskStatusEnum.InProgress,
mySessionId = mySessionId
},
transaction: tran
);
if (chosen == null)
{
throw new InvalidOperationException();
}
var expiry = await db.ExecuteAsync("UPDATE TaskStatus SET Status = @status WHERE TaskId = @taskId", new {status = TaskStatusEnum.Done, taskId = chosen.TaskId}, tran);
tran.Commit();
return chosen;
}
catch
{
tran.Rollback();
throw;
}
}
}
}
谢谢你的回复。一些后续行动。1.隔离级别应该是什么?2.当我们看到问题时,Web API不会抛出错误。3.使用Dapper时的惯例是将SQL包含在代码中-这取决于个人喜好。隔离级别取决于您的项目要求,在这种情况下很难说具体的隔离级别,可能会产生误导。但是你可以在谷歌上找到合适的隔离级别,我们只有四个隔离级别。另一个选项是Web API也可以抛出和出错,但有点奇怪,请搜索WebFaultException,Dapper是最好的ORM之一,但如果您管理非常大的对象,您可能会像其他ORM一样出现性能问题。我希望有帮助。请你进一步解释你的解决方案好吗?我不明白。谢谢,这是一个有趣的解决方案。