前言
.net 环境近些年也算是稳步发展。在开发的过程中,与数据库打交道是必不可少的。早期的开发者都是DbHelper一撸到底,到现在的各种各样的ORM框架大行其道。孰优孰劣谁也说不清楚,文无第一武无第二说的就是这个理。没有什么最好的,只有最适合你的。
本人也是从DbHelper开始,期间用过SugarSql,再到EFCODE。本着学习分享的初衷分享本人工作中总结的一些小技巧,希望能帮助更多开发者,期望能达到共同进步。文中若有错误地方,欢迎大家不吝赐教。
1. DbContext配置
在asp.net中,通常情况下,通过在Startup类的ConfigureServices方法中,将ef服务注入。
示例代码如下:
services.AddDbContext<DemoDbContext>(opt=>opt.UseMySql("server=.;Database=demo;Uid=root;Pwd=123;Port=3306;"));
以上代码表示使用MySql数据库。如果使用SqlServer数据库,可以把UseMySql改为UseSqlServer,其他数据库的使用方式也是通过调用不同的方法进行选择。但需要安装对应的扩展方法的程序包,如 Microsoft.EntityFrameworkCore.SqlServer 或 Microsoft.EntityFrameworkCore.Sqlite。
另外,UseMySql方法还包含了一个可空的Action 类型的参数,可以通过此参数进行一些个性化的配置,比如配置重试机制。如下所示:
services.AddDbContext<DemoDbContext>(opt => opt.UseMySql("server=.;Database=demo;Uid=root;Pwd=123456;Port=3306;",
provideropt => provideropt.EnableRetryOnFailure(3,TimeSpan.FromSeconds(10),new List<int>(){0} )));
这个重试机制在某些场景下还是比较有用的。比如,由于网络波动或访问量导致的一瞬间的连接超时。如果不设置重试机制,则会直接触发异常,设置了超时后,则会根据设置的时间间隔以及重试次数进行重试。EnableRetryOnFailure方法的最后一个参数是用来设置错误代码的,只有设置了错误代码的错误,才会触发重试。获取错误代码的方法有很多种,个人比较推荐的是,通过异常信息进行获取,比如,使用MySql数据时,触发的异常类型是MySqlException,此类的Number属性的值EnableRetryOnFailure方法所需要的Number
2. DbContext线程问题
efcore不支持在同一个DbContext实例上运行多个并行操作,这包括异步查询的并行执行以及从多个线程进行的任何显式并发使用。 因此,始终 await 异步调用,或对并行执行的操作使用单独的 DbContext 实例。
当 EF Core 检测到并行操作或多个线程同时尝试使用 DbContext 实例时,你将看到一条 InvalidOperationException,其中包含类似于下面的消息:
A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
意思是,在上一个操作没有执行完毕之前,又启动了一个新的操作,所以不能保证线程是安全的。
下面是一段错误的,可以触发这个异常的示例代码:
所以,请始终await异步调用。如果在多个多个线程中使用DbContext,需保证每个线程的DbContext的实例是唯一的。
3. 数据库使用连接池
使用 services.AddDbContextPool比使用 services.AddDbContext吞吐量提升在10~20的百分点(非官方说法,对性能提高数据是本人测试后得到的结果)。
需要注意的是,连接池大小并不是越大越好。