The database operation was expected to affect 1 row(s), but actually affected 0 row(s); 解决乐观并发

the,database,operation,was,expected,to,affect,row,but,actually,affected,解决,乐观,并发 · 浏览次数 : 43

小编点评

## 乐观并发EF Core 实现乐观并发 **乐观并发**是一种数据库操作并发处理的技术,它可以让多个用户同时访问同一个数据库记录,但避免数据丢失或出现错误。在EF Core中,乐观并发可以用**`UseIdentityColumn`**配置属性实现。 **乐观并发的步骤:** 1. **设置乐观锁**:使用 `UseIdentityColumn` 配置属性设置表的主键为 **`IdentityColumn`**。 2. **读取数据**:在 `SaveChanges` 方法之前,读取数据库中的记录并存储在 **`OriginalValues`** 中。 3. **执行更改**:执行数据库中的修改操作。 4. **更新乐观锁**:在操作完成后,更新 **`OriginalValues`** 中的 **`ModifiedDate`** 属性,以表明数据已更新。 5. **处理并发冲突**:如果多个用户在同一时间访问相同的记录,乐观锁会失败,并引发 **`DbUpdateConcurrencyException`**。 6. **报告并发冲突**:异常中包含修改的记录,应用程序可以通过这些记录跟踪数据变更。 **乐观并发允许发生并发冲突的原因:** * **并发插入:**多个用户可能同时向数据库中插入相同的记录。 * **并发更新:**多个用户可能同时向数据库中更新同一个记录。 * **并发删除:**多个用户可能同时向数据库中删除同一个记录。 **解决方案:** * 在 `SaveChanges` 方法中,使用 `OriginalValues` 存储原始数据,并在处理并发冲突时将其恢复。 * 使用 `concurrencyToken` 和 `cancellationToken` 来处理并发操作,并确保数据完整性。 * 在异常中处理并发冲突并提供有关数据变更的信息。

正文

The database operation was expected to affect 1 row(s), but actually affected 0 row(s); 解决乐观并发

1.乐观并发

EF Core 实现 乐观并发,假定并发冲突相对较少。 与 悲观 方法(即先锁定数据,然后才继续修改数据)不同,乐观并发不需要锁定,而是安排数据修改在保存时失败(如果数据自查询后已更改)。 此并发故障将报告给应用程序,应用程序可能会通过对新数据重试整个操作来相应地处理它。

在 EF Core 中,乐观并发是通过将属性配置为 并发令牌来实现的。 在查询实体时加载和跟踪并发令牌,就像任何其他属性一样。 然后,在 期间 SaveChanges()执行更新或删除操作时,数据库上的并发令牌值与 EF Core 读取的原始值进行比较。

代码触发乐观会如下错误:

Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.

2.设置乐观锁

我的程序使用EF Core,然后给实体类设置了乐观并发 UseIdentityColumn

 public void Configure(EntityTypeBuilder<ChatRecord> builder)
 {
 //在 PostgreSQL 中,表名以及列名是不区分大小写的。这意味着在数据库中创建表时,无论您是使用大写、小写或混合大小写的名称,最终都会使用相同的名称来访问和操作该表。
 //设置表
 builder.ToTable("ChatRecord");
 //设置表主键
 builder.HasKey(e => e.ChatRecordId);
 //设置主键自增
 builder.Property(e => e.ChatRecordId)
 .UseIdentityColumn();
}

3.什么情况下会触发乐观并发

乐观并发允许发生并发冲突,并在并发冲突发生时作出正确反应。 例如,Jane 访问院系编辑页面,将英语系的预算从 350,000.00 美元更改为 0.00 美元。

将预算更改为零

在 Jane 单击“保存”之前,John 访问了相同页面,并将开始日期字段从 2007/1/9 更改为 2013/1/9。

将开始日期更改为 2013

Jane 单击“保存”后看到更改生效,因为浏览器会显示预算金额为零的“索引”页面。

John 单击“编辑”页面上的“保存”,但页面的预算仍显示为 350,000.00 美元。 接下来的情况取决于并发冲突的处理方式:

  • 跟踪用户已修改的属性,并仅更新数据库中相应的列。

    在这种情况下,数据不会丢失。 两个用户更新了不同的属性。 下次有人浏览英语系时,将看到 Jane 和 John 两个人的更改。 这种更新方法可以减少导致数据丢失的冲突数。 这种方法具有一些缺点:

    • 无法避免数据丢失,如果对同一属性进行竞争性更改的话。
    • 通常不适用于 Web 应用。 它需要维持重要状态,以便跟踪所有提取值和新值。 维持大量状态可能影响应用性能。
    • 可能会增加应用复杂性(与实体上的并发检测相比)。
  • 让 John 的更改覆盖 Jane 的更改。

    下次有人浏览英语系时,将看到 2013/9/1 和提取的值 350,000.00 美元。 这种方法称为“客户端优先”或“最后一个优先”方案 。 客户端的所有值优先于数据存储的值。 基架代码不处理并发,“客户端优先”方案会自动执行。

  • 阻止在数据库中更新 John 的更改。 应用通常会:

    • 显示错误消息。
    • 显示数据的当前状态。
    • 允许用户重新应用更改。

    这称为“存储优先”方案。 数据存储值优先于客户端提交的值。 本教程中使用了“存储优先”方案。 此方法可确保用户在未收到警报时不会覆盖任何更改。

4.解决方案:重写SaveChanges

在 FrameworkDbContext 的DbContext类中重写SaveChanges方法

image-20230824173508331

代码如下:

 public override int SaveChanges()
        {
            var saved = 0;
            while (saved ==0) {
                try {
                    base.SaveChanges();
                    saved++;
                }
                catch (DbUpdateConcurrencyException ex) {
                    foreach (var entry in ex.Entries) {
                            var proposedValues = entry.CurrentValues;
                            var databaseValues = entry.GetDatabaseValues();

                            foreach (var property in proposedValues.Properties) {
                                var proposedValue = proposedValues[property];
                                var databaseValue = databaseValues[property];
                            }

                            // Refresh original values to bypass next concurrency check
                            entry.OriginalValues.SetValues(databaseValues);
                    }
                }
            }

            return saved;
        }

代码可以在github中查找。我的开源项目修改的类的源码,源码地址:https://github.com/TerraMours/TerraMours_Gpt_Api/blob/main/TerraMours/TerraMours/Framework/Infrastructure/EFCore/FrameworkDbContext.cs

参考资料:https://learn.microsoft.com/zh-cn/ef/core/saving/concurrency?tabs=fluent-api

阅读如遇样式问题,请前往个人博客浏览: https://www.raokun.top

拥抱ChatGPT:https://first.terramours.site

开源项目地址:https://github.com/TerraMours/TerraMours_Gpt_Api

与The database operation was expected to affect 1 row(s), but actually affected 0 row(s); 解决乐观并发相似的内容:

The database operation was expected to affect 1 row(s), but actually affected 0 row(s); 解决乐观并发

# [The database operation was expected to affect 1 row(s), but actually affected 0 row(s); 解决乐观并发](https://www.raokun.top/archives/thedatabaseoperatio

5/13 死神永生服周报创刊号

目录 1.死神永生新用户必读 2.死神永生周刊说明 死神永生新用户必读 你好,欢迎来到死神永生服,也欢迎来看我们服的周报,感谢对我服的支持! 如果你是新手,请你抽出一分钟看看我们服务器的基本介绍和一些规则,谢谢。 在伟大的Bloxd社区中,有不少中国人创建的服务器,但其中用户很多的国服包括伟大服、B

[转帖]The USE Method

Boeing 707 Emergency Checklist(1969) The Utilization Saturation and Errors (USE) Method is a methodology for analyzing the performance of any system.

[转帖]The necessary bits to build these optional modules were not found: _uuid _bz2 _curse _curses_panel

在安装Python3.7可能遇到如题的错误,只需安装uuid库就可以 ubuntu下安装uuid链接库 sudo apt-get install uuid-dev CentOS yum install libuuid-devel 对于以下的问题 The necessary bits to build

[转帖]THE REST OF THE WORLD CAN FINALLY GET SAPPHIRE RAPIDS XEON SPS

https://www.nextplatform.com/2023/01/10/the-rest-of-the-world-can-finally-get-sapphire-rapids-xeon-sps/ If you are thinking that you are having flashb

[转帖]2.6 The jcmd Utility

https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr006.html#BABEJDGE The jcmd utility is used to send diagnostic command req

[转帖]THE OSWATCHER ANALYZER USER'S GUIDE

oswbba THE OSWATCHER ANALYZER USER'S GUIDE Carl DavisMay 7, 2019 To see how to use this tool and it's different features you can view a series of shor

[转帖]TiKV Config Learn the TiKV configuration file

The TiKV configuration file supports more options than command-line parameters. You can find the default configuration file in etc/config-template.tom

[转帖]PD Config Learn the PD configuration file

The PD configuration file supports more options than command-line parameters. You can find the default configuration file here. This document only des

Neo4j Neo.TransientError.General.MemoryPoolOutOfMemoryError

The allocation of an extra 4.0 MiB would use more than the limit 2.0 GiB. Currently using 2.0 GiB. dbms.memory.transaction.total.max threshold reached