EF Core 的并发处理
概念
并发问题是一个常见的问题,很多人认为并发只会发生在数据库操作上,其实不然,它一样可以发生在文件的读写操作上。只要我们从服务器访问资源并更新,就有可能会发生并发。但我们在开发中更多的是连接数据库来操作数据,所以我们习惯性的认为并发是数据库并发。
并发是指两个或多个用户试图同时修改同一资源造成的冲突。比如,A君读取数据以更新数据,但B君在A君更新数据之前先更新数据,A君更新操会导致三个值之间发生冲突。这三个值分别:
-
A君读取到的值(原始值)
-
B君更新的值(数据库值)
-
A君正在更新的值(当前值)
这种并发冲突如果不做任何处理会造成数据前后的不一致和完整性。比如:下单和退货发生并发冲突时将造成库存不一致,后果可想而知。
我们通过并发检测和解决并发冲突称为并发处理。
并发处理是一种机制,使众多用户能够同时访问相同的资源,同时确保资源在未来所有请求中保持数据的安全性、完整性和一致。
处理并发冲突有两种解决方法:乐观并发和悲观并发策略。
悲观并发
悲观并发每次访问资源时都上锁,使得其它用户无法访问该资源。这种策略就是假设用户每次访问资源都认定会更新资源,所以每次访问资源就上锁,当资源被修改时,同一资源上的所有其它并发操作都将被暂停,直到当前操作完成,并且该资源上的锁被释放。
这种方法在资源争用较高的场景中是一个不错的选择。可以在锁定持续时间较短的场景中利用悲观并发。但是,当用户与数据交互时,悲观并发不能很好的扩展,会导致资源锁住很长的时间。再者当互联网连接较弱或断开连接时,将无法正确管理数据,这会影响数据库的工作。
乐观并发
乐观并发假设用户每次访问资源都不会更新资源,所以资源不会被锁定。但是在更新的时候会判断在此期间其它用户是否有更新操作。
乐观并发遵循“保存最新数据”的策略。
乐观并发通常用于数据稀缺的场景,也就是常说的频繁读取,这样可以提高吞吐量,但也会消耗额外的服务器资源 。
乐观并发提高了性能也更好的支持扩展,因为它允许服务器在更短时间内为更多的客户端提供服务。
今天,我们来讨论 EF Core 是怎么处理数据库并发。在EF Core 中是不支持悲观并发,但有两种方式可用于乐观并发来进行并发冲突检测。
一种是将实体配置为并发令牌;另一种是在实体类中添加行版本属性。
使用并发令牌
Data Annotation 配置方式
-
public class Users
-
{
-
public int Id { get; set; }
-
public string UserName { get; set; }
-
public string PasswordHash { get; set; }
-
[]
-
public string ConcurrencyStamp { get; set; }
-
}
Fluent API 配置方式
-
protected override void OnModelCreating(ModelBuilder modelBuilder)
-
{
-
modelBuilder.Entity<Users>()
-
.Property(p => p.ConcurrencyStamp)
-
.IsConcurrencyToken();
-
}
两种配置方式选择一种即可,使用并发令牌 EF Core 不会自动生成值,我们在更新实体记得给 ConcurrencyStamp 赋值。
使用版本属性
Data Annotation 配置方式
-
public class Roles
-
{
-
public int Id { get; set; }
-
public string Name { get; set; }
-
public string Description { get; set; }
-
[]
-
public byte[] Timestamp { get; set; }
-
}
Fluent API 配置方式
-
protected override void OnModelCreating(ModelBuilder modelBuilder)
-
{
-
modelBuilder.Entity<Roles>()
-
.Property(p => p.Timestamp)
-
.IsRowVersion();
-
}
也是两种选择一种,但与并发令牌不同的是不用给 Timestamp 赋值,EF Core 会自动产生一个值。
配置完之后 ,实体执行更新或删除操作时,EF Core 都会将请求中的信息值与数据库表中的值进行比较。
-
如果两个值匹配,则执行操作。
-
如果值不匹配,则更新或删除操作将中止并且抛出一个 DbUpdateConcurrencyException。
当 EF Core 抛出 DbUpdateConcurrencyException ,我们可以做如下选择进行处理:
-
中止操作并要求用户刷新界面重新操作,称为使用他的,但会覆盖本地的操作数据。
-
使用当前值(最新一次提交的数据)并尝试重新 SaveChanges ,称为使用我的,但会覆盖服务器上的数据。
-
将冲突记录下来,让用户自己选择使用那个数据,称为手动解决。这种方式始终保持数据最新。
以下是个简单的冲突处理代码:
-
using (var context = new ApplicationDbContext())
-
{
-
var role = context.Roles.Single(p => p.Id == 1);
-
role.Name = "administrators";
-
-
context.Database.ExecuteSqlRaw(
-
"UPDATE dbo.Roles SET Description = '管理员组' WHERE Id = 1");
-
-
var savedData = false;
-
-
while (!savedData)
-
{
-
try
-
{
-
// 更新到数据库
-
context.SaveChanges();
-
savedData = true;
-
}
-
catch (DbUpdateConcurrencyException ex)
-
{
-
foreach (var item in ex.Entries)
-
{
-
if (item.Entity is Roles)
-
{
-
var currentValues = entry.CurrentValues;
-
var dbValues = entry.GetDatabaseValues();
-
-
foreach (var prop in currentValues.Properties)
-
{
-
var currentValue = currentValues[prop];
-
var dbValue = dbValues[prop];
-
}
-
-
// 刷新原始值以绕过下一次并发检查
-
item.OriginalValues.SetValues(dbValues);
-
}
-
else
-
{
-
throw new NotSupportedException( "未处理的并发冲突:" item.Metadata.Name);
-
}
-
}
-
}
-
}
-
}
这个示例只是说明下 DbUpdateConcurrencyException 里的 Entries 及三种值。
EF Core 并发处理就到这。
祝大家学习愉快!
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhiaaggc
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
微信运动停用后别人还能看到步数吗
PHP中文网 07-22