.net core 数据库查询不涉及事务

.net core 数据库查询不涉及事务,.net-core,dapper,.net Core,Dapper,我有一段代码,用来一次一个地从数据库中提取项目。每次get时,它都会更新行的状态,以指示已检索该行,从而不会多次检索同一行 下面的代码是从为Web API提供服务的后端服务运行的。有时,当多个请求传入时,它将返回具有相同ID的同一行任务 我的印象是,有一个事务围绕着它,这意味着其中一个运行的更新将阻止第二个查询返回该行 任何帮助都将不胜感激 public async Task<TaskDetail> GetTask() { using (var db = new SqlCon

我有一段代码,用来一次一个地从数据库中提取项目。每次get时,它都会更新行的状态,以指示已检索该行,从而不会多次检索同一行

下面的代码是从为Web API提供服务的后端服务运行的。有时,当多个请求传入时,它将返回具有相同ID的同一行任务

我的印象是,有一个事务围绕着它,这意味着其中一个运行的更新将阻止第二个查询返回该行

任何帮助都将不胜感激

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一样出现性能问题。我希望有帮助。请你进一步解释你的解决方案好吗?我不明白。谢谢,这是一个有趣的解决方案。