ASP.NET Core 中的 ORM 之 Entity Framework (3)

数据库并发指的是多个进程或用户同时访问或更改数据库中的相同数据的情况。 并发控制指的是用于在发生并发更改时确保数据一致性的特定机制。

乐观并发:无论何时从数据库请求数据,数据都会被读取并保存到应用内存中。数据库级别没有放置任何显式锁。数据操作会按照数据层接收到的顺序执行。

悲观并发:无论何时从数据库请求数据,数据都会被读取,然后该数据上就会加锁,因此没有人能访问该数据。这会降低并发相关问题的机会,缺点是加锁是一个昂贵的操作,会降低整个应用程序的性能。

EF Core 默认支持乐观并发控制,这意味着它将允许多个进程或用户独立进行更改而不产生同步或锁定的开销。 在理想情况下,这些更改将不会相互影响,因此能够成功。 在最坏的情况下,两个或更多进程将尝试进行冲突更改,其中只有一个进程应该成功。

ConcurrencyCheck / IsConcurrencyToken
ConcurrencyCheck 特性可以应用到领域类的属性中。当EF执行更新或删除操作时,EF Core 会将配置的列放在 where 条件语句中。执行这些语句后,EF Core 会读取受影响的行数。如果未影响任何行,将检测到并发冲突引发 DbUpdateConcurrencyException。

public class Blog { public int BlogId { get; set; } public string Url { get; set; } [ConcurrencyCheck] public int Rating { get; set; } } [HttpPut("{id}")] public async Task<IActionResult> PutBlog([FromRoute] int id, [FromBody] Blog blog) { if (!ModelState.IsValid) { return BadRequest(ModelState); } var dbModel = await _context.Blogs.FindAsync(id); dbModel.Url = blog.Url; dbModel.Rating = blog.Rating; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException ex) { //todo: handle DbUpdateConcurrencyException throw ex; } return NoContent(); }

通过 SQL Server Profiler 查看生成的 SQL Update 语句。

exec sp_executesql N'SET NOCOUNT ON; UPDATE [Blogs] SET [Rating] = @p0, [Url] = @p1 WHERE [BlogId] = @p2 AND [Rating] = @p3; SELECT @@ROWCOUNT; ',N'@p2 int,@p0 int,@p3 int,@p1 nvarchar(500)',@p2=1,@p0=999,@p3=20,@p1=N'http://sample.com/1'

Timestamp / IsRowVersion
TimeStamp特性可以应用到领域类中,只有一个字节数组的属性上面。每次插入或更新行时,由数据库生成一个新的值做为并发标记。

public class Blog { public int BlogId { get; set; } public string Url { get; set; } public int Rating { get; set; } [Timestamp] public byte[] Timestamp { get; set; } }

通过 SQL Server Profiler 查看生成的 SQL Update 语句。

exec sp_executesql N'SET NOCOUNT ON; UPDATE [Blogs] SET [Rating] = @p0 WHERE [BlogId] = @p1 AND [Timestamp] = @p2; SELECT [Timestamp] FROM [Blogs] WHERE @@ROWCOUNT = 1 AND [BlogId] = @p1; ',N'@p1 int,@p0 int,@p2 varbinary(8)',@p1=1,@p0=8888,@p2=0x00000000000007D1

处理冲突的策略:

忽略冲突并强制更新:这种策略是让所有的用户更改相同的数据集,然后所有的修改都会经过数据库,这就意味着数据库会显示最后一次更新的值。这种策略会导致潜在的数据丢失,因为许多用户的更改都丢失了,只有最后一个用户的更改是可见的。

部分更新:在这种情况中,我们也允许所有的更改,但是不会更新完整的行,只有特定用户拥有的列更新了。这就意味着,如果两个用户更新相同的记录但却不同的列,那么这两个更新都会成功,而且来自这两个用户的更改都是可见的。

拒绝更改:当一个用户尝试更新一个记录时,但是该记录自从他读取之后已经被别人修改了,此时告诉该用户不允许更新该数据,因为数据已经被某人更新了。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgffdz.html