kka*_*4sz 12 c# sql-server entity-framework-core .net-core
所以我遇到了死锁问题,我得到了这个异常:
System.InvalidOperationException: An exception has been raised that is likely due to a transient failure. Consider enabling transient error resiliency by adding 'EnableRetryOnFailure()' to the 'UseSqlServer' call.
我什至制作了第二个项目来编写最简单的代码,这会导致同样的问题,它只是几行代码。这非常基本,您只需要有两个引用相同不同实体的实体即可。在我看来,这是很常见的事情,EF Core 默认情况下无法处理此问题,并提示使用EnableRetryOnFailure()
.
我认为两个或多个实体与同一实体有关系是很常见的。我们甚至可以在我们的应用程序中拥有类似日志系统的东西,每当有人添加数据时,它就会向数据库中的日志表添加记录,并且数据总是与某些日志记录相关。或者我们可以保存哪个用户添加了一些数据等。可能性是无限的。
我的问题是:如果我们有大型应用程序,那么每秒 1000 个用户可能会触发重试,具体取决于他们使用导致死锁的某些操作的频率。这不会损害性能吗?这最终不会堵塞数据库吗?
为了简单起见,它只是一个 API,所有代码都位于控制器内。数据库由 EF Core 生成(代码优先方法)。它有两个控制器,其端点接受带有添加到数据库的数据的 json 文件。每次将文件中的数据添加到数据库时,都会保存有关文件的信息(文件名、日期和时间)。发布一个文件会产生许多包含数据的记录(取决于内部内容)以及一个包含文件名、日期和时间的记录(每个数据记录都会获取相同的文件引用,因此所有记录都将具有相同的 InputFileId)。
您只需同时向两个端点发送请求即可。或者只是同时向同一个端点发送 4 个请求。我的 json 文件中有 2000 个条目,因此需要更长的时间才能更容易触发死锁。
用户控制器:
[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
public MyDbContext DbContext { get; }
public UsersController(MyDbContext dbContext)
{
DbContext = dbContext;
}
[HttpPost]
public async Task<IActionResult> Import([FromForm]IFormFile file)
{
using var streamReader = new StreamReader(file.OpenReadStream());
JsonSerializer serializer = new JsonSerializer();
List<User> users = (List<User>)serializer.Deserialize(streamReader, typeof(List<User>));
var inputFile = new InputFile
{
FileName = file.FileName,
DateAdded = DateTime.Now
};
foreach (var user in users)
{
user.InputFile = inputFile;
}
await DbContext.AddRangeAsync(users);
await DbContext.SaveChangesAsync();
return Ok();
}
}
Run Code Online (Sandbox Code Playgroud)
产品控制器:
[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
public MyDbContext DbContext { get; }
public ProductsController(MyDbContext dbContext)
{
DbContext = dbContext;
}
[HttpPost]
public async Task<IActionResult> Import([FromForm]IFormFile file)
{
using var streamReader = new StreamReader(file.OpenReadStream());
JsonSerializer serializer = new JsonSerializer();
List<Product> products = (List<Product>)serializer.Deserialize(streamReader, typeof(List<Product>));
var inputFile = new InputFile
{
FileName = file.FileName,
DateAdded = DateTime.Now
};
foreach (var product in products)
{
product.InputFile = inputFile;
}
await DbContext.AddRangeAsync(products);
await DbContext.SaveChangesAsync();
return Ok();
}
}
Run Code Online (Sandbox Code Playgroud)
数据库上下文:
public class MyDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<InputFile> InputFiles { get; set; }
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
{
}
}
Run Code Online (Sandbox Code Playgroud)
产品:
public class Product
{
public long Id { get; set; }
public string SerialNumber { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public long InputFileId { get; set; }
public InputFile InputFile { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
用户:
public class User
{
public long Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public long InputFileId { get; set; }
public InputFile InputFile { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
输入文件:
public class InputFile
{
public long Id { get; set; }
public string FileName { get; set; }
public DateTime DateAdded { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
Startup.cs,配置服务:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
Run Code Online (Sandbox Code Playgroud)
lau*_*jpn 10
这最终不会堵塞数据库吗?
默认EnableRetryOnFailure
实现会增加重试之间的等待时间。因此,它通常开箱即用,甚至不需要您进行调整。
这不会损害性能吗?
不,事实并非如此。
如果我们有大型应用程序,那么每秒可能有 1000 个用户触发重试,具体取决于他们使用导致死锁的某些操作的频率。
还要确保您已READ_COMMITTED_SNAPSHOT
设置为ON
.
有关详细信息,请参阅连接弹性。另请查看SqlServerRetryingExecutionStrategy和ExecutionStrategy实现。
归档时间: |
|
查看次数: |
18908 次 |
最近记录: |