在提交事务和 (UPDLOCK, HOLDLOCK) 之前返回一个值

Returning a value before committing transaction and (UPDLOCK, HOLDLOCK)

我需要检查记录是否存在 - 如果存在:那么 returns 它的 ID,如果不存在:创建一个新记录和 returns 它的 ID。我在 SELECT 中使用 WITH (UPDLOCK, HOLDLOCK) 来防止重复(它会创建锁)。请问如果数据库中存在一条实现锁的记录是否要提交事务?

using (SqlConnection connection = new SqlConnection("..."))
{
    await connection.OpenAsync();
    using (var transaction = connection.BeginTransaction())
    {
        var locationId = await connection.QueryFirstOrDefaultAsync<int?>(
                "SELECT id 
                 FROM Locations WITH (UPDLOCK, HOLDLOCK)
                 WHERE regionId = @RegionId", new { RegionId = 1 }, transaction: transaction
            );

        if (locationId.HasValue)
        {
            //transaction.Commit(); // should I commit the transaction here?
            return locationId.Value;
        }

        var location = new Location()
        {
            Name = "test",
            RegionId = 1
        };

        var newLocationid = await connection.InsertAsync<int>(location, transaction);

        transaction.Commit();

        return newLocationid;                    
    }
}   

should I commit the transaction here?

是的。否则它会在 using 块完成时回滚。在这种特殊情况下这无关紧要,但最好明确说明。如果这个交易是一个更大交易的一部分,整个事情就会回滚。

这里不需要交易。

using (SqlConnection connection = new SqlConnection("..."))
{
    await connection.OpenAsync();
    /* The lock hints you had here makes no sense. */
    var locationId = await connection.QueryFirstOrDefaultAsync<int?>(
            "SELECT id 
             FROM Locations
             WHERE regionId = @RegionId", new { RegionId = 1 }
        );

    if (locationId.HasValue)
    {
        return locationId.Value;
    }

    var location = new Location()
    {
        Name = "test",
        RegionId = 1
    };

    /* INSERT has an implicit transaction 
       only need to use a transaction if you have multiple DML statements (i.e. INSERT, UPDATE or DELETE statments) */
    var newLocationid = await connection.InsertAsync<int>(location);
    return newLocationid;                    
}

}

好吧,您不必在查询时开始交易。您可以按如下方式重写代码:

    using (SqlConnection connection = new SqlConnection("..."))
    {
        await connection.OpenAsync();
        var locationId = await connection.QueryFirstOrDefaultAsync<int?>(
                    "SELECT id 
                     FROM Locations WITH (UPDLOCK, HOLDLOCK)
                     WHERE regionId = @RegionId", new { RegionId = 1 });
    
        if (locationId.HasValue)
        {
            return locationId.Value;
        }
    
        using (var transaction = connection.BeginTransaction())
        {
            var location = new Location()
            {
                Name = "test",
                RegionId = 1
            };
    
            var newLocationid = await connection.InsertAsync<int>(location, transaction);
    
            transaction.Commit();
        }

        return newLocationid;
    }