sql-server 使用EFCore和SQL Server防止对单个表进行并发读取

tmb3ates  于 2022-10-31  发布在  SQL Server
关注(0)|答案(1)|浏览(226)

我有下面的场景..
1.创建员工记录

  1. NextPayrollNumber从数据库表(设置表)中的记录读取
    1.编号以1递增,并作为PayrollNumber添加到Employee记录中,同时覆盖当前NextPayrollNumber
    1.雇员记录保存到数据库(雇员表)
    我需要确保两个Employee记录不会有相同的编号,我做了一些搜索,看起来并发问题通常是通过Concurrency Token和在DBContext中进行并发异常处理来处理的。但这涉及到向设置表中添加另一列以存储rowversion,并向dbcontext中添加仅用于这一要求的代码,而应用程序的其余部分则不需要。我不需要。
    是否有其他方法来处理这个问题?我希望向数据库表添加一个唯一的约束(但列将具有空值),或者使用一个序列,但值需要基于最终用户可配置的NextPayrollNumber。
7d7tgy0s

7d7tgy0s1#

假设工资单编号不是该行的主键(使用内置标识),并且您不希望从PK标识派生工资单编号,那么我的建议是,为了安全起见,不要担心同时发生2次插入的异常情况,而是通过重试来处理该异常,对工资单编号具有唯一约束。基本上,填充工资单编号并尽快保存记录,如果遇到重复的异常(这种情况应该很少发生),请从设置中提取新的工资单编号(确保重新加载设置实体或从数据库中提取而不是从缓存行中提取),然后再次保存,必要时重试。如果下一个编号与检索的编号相同,则说明插入操作存在更大的问题,并可以通过异常消息退出。

var settings = _context.Settings.Single(); // However this is loaded, whether single row or row per Tenant...

var customer = new Customer 
{
   // populate values...
   PayrollNumber = settings.NextPayrollNumber++;
};
int retryCount = 0;
bool complete = false;
while(retryCount < 5 && !complete)
{
     try
     {
        _context.SaveChanges();
        complete = true;
     }
     catch (SqlException ex)
     {
        var constraintErrorNumbers = new[] {547, 2601, 2627}; // SQL codes around constraint violations.
        if (constraintErrorNumbers.Contains(ex.Number)
        {
            _context.Entry(settings).Reload(); //Refresh the settings from the DB.
            int currentPayrollNumber = customer.PayrollNumber;
            customer.PayrollNumber = settings.NextPayrollNumber++;
            if(customer.PayrollNumber == currentPayrollNumber)
                throw; // It wasn't the payroll number that was duplicated because the sequence hasn't changed.
            retryCount++;
        }
        else
            throw;
     }
}

您很可能需要捕获EF InsertException或UpdateException之类的异常,而不是SqlException,并检查应该是SqlException的InnerException。
这将更新设置中的NextPayrollNumber,并成功保存新客户。
通常,我不建议在表中为工资单编号等内容保留一个Sequence,而是生成/选择一个“应该是唯一的”值,如随机数、雪花或哈希等,以构建和验证新的工资单编号。需要应用相同的重试逻辑来处理罕见的重复情况,但这不会依赖于协调插入到一个序列。

相关问题