<ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>


      DbContextPool 是 ASP.NET Core 2.1 引入的新特性,可以節(jié)省創(chuàng)建 DbContext 實(shí)例的開銷,但沒(méi)有想到其中藏著一個(gè)小坑。

      最近有一個(gè) ASP.NET Core 項(xiàng)目持續(xù)運(yùn)行一段時(shí)間后日志中就會(huì)出現(xiàn)數(shù)據(jù)庫(kù)連接池達(dá)到最大連接數(shù)限制的錯(cuò)誤:
      System.InvalidOperationException: Timeout expired. The timeout period elapsed
      prior to obtaining a connection from the pool. This may have occurred because
      all pooled connections were in use and max pool size was reached. at
      System.Data.Common.ADP.ExceptionWithStackTrace(Exception e)
      開始以為是哪個(gè)地方的代碼造成 DbContext 不能正常 Dispose ,但在代碼中沒(méi)有找到任何相關(guān)線索。后來(lái)實(shí)在沒(méi)有其他可以懷疑的地方,唯有
      DbContextPool ,于是嘗試去掉 DbContextPool ,結(jié)果錯(cuò)誤就消失了。果然是 DbContextPool 引起的,但讓人納悶的是
      DbContextPool 本來(lái)就是為了節(jié)省創(chuàng)建 DbContext
      實(shí)例的開銷,怎么反而消耗更多數(shù)據(jù)庫(kù)連接,而且這個(gè)項(xiàng)目的負(fù)載很低,怎么可能把整個(gè)連接池都消耗殆盡呢?

      今天在周會(huì)上談了這個(gè)怪問(wèn)題,后來(lái)突然想到:每個(gè) DbContext 實(shí)例都會(huì)占用一個(gè)數(shù)據(jù)庫(kù)連接(SqlConnection),不啟用
      DbContextPool 的時(shí)候,請(qǐng)求一結(jié)束,對(duì)應(yīng) DbContext 實(shí)例就被 Dispose ,數(shù)據(jù)庫(kù)連接就會(huì)被放回連接池。而使用
      DbContextPool 的時(shí)候,請(qǐng)求結(jié)束后 DbContext 不會(huì)被 Dispose 而是被放回 DbContextPool ,DbContext
      被放回屬于自己的池中,就意味它對(duì)應(yīng)的數(shù)據(jù)庫(kù)連接不會(huì)被放回它所屬的連接池。DbContextPool 中的每一個(gè) DbContext
      都對(duì)應(yīng)一個(gè)數(shù)據(jù)庫(kù)連接,DbContextPool 中每多一個(gè) DbContext ,數(shù)據(jù)庫(kù)連接池中就會(huì)少一個(gè)數(shù)據(jù)庫(kù)連接。當(dāng)這兩個(gè)池的大小不一樣且
      DbContextPool 大于數(shù)據(jù)庫(kù)連接池,問(wèn)題就來(lái)了,DbContextPool 根據(jù)自家池(假設(shè)是128)子的大小暢快地向池中填 DbContext
      ,渾然不顧數(shù)據(jù)庫(kù)連接池的大小(假設(shè)是100),當(dāng)填到第 101 個(gè) DbContext 時(shí)就會(huì)出現(xiàn)上面的錯(cuò)誤。

      這個(gè)項(xiàng)目中用的都是默認(rèn)設(shè)置,是不是默認(rèn)設(shè)置就會(huì)觸發(fā)這個(gè)問(wèn)題呢?

      查看 DbContextPool 的 實(shí)現(xiàn)源碼
      <https://github.com/aspnet/EntityFrameworkCore/blob/release/2.2/src/EFCore/EntityFrameworkServiceCollectionExtensions.cs#L145>
      發(fā)現(xiàn)池的默認(rèn)大小限制是 128
      public static IServiceCollection AddDbContextPool<TContext>( [NotNull] this
      IServiceCollection serviceCollection, [NotNull] Action<DbContextOptionsBuilder>
      optionsAction, int poolSize = 128) where TContext : DbContext =>
      AddDbContextPool<TContext, TContext>(serviceCollection, optionsAction,
      poolSize);
      查看 SqlConnention 的 實(shí)現(xiàn)源碼
      <https://github.com/dotnet/corefx/blob/release/2.2/src/System.Data.SqlClient/src/System/Data/SqlClient/SqlConnectionString.cs#L35>
      發(fā)現(xiàn)連接池的默認(rèn)大小限制是 100
      internal const int Max_Pool_Size = 100;
      默認(rèn)設(shè)置就會(huì)觸發(fā)問(wèn)題,實(shí)實(shí)在在的一個(gè)小坑。

      知道了原因,解決起來(lái)就很簡(jiǎn)單了,將 DbContextPool 的 poolSize 設(shè)置為小于數(shù)據(jù)庫(kù)連接池的 Max_Pool_Size
      services.AddDbContextPool<JobDb>(option =>
      option.UseSqlServer(Configuration.DbConnectionStr()), poolSize: 64);

      友情鏈接
      ioDraw流程圖
      API參考文檔
      OK工具箱
      云服務(wù)器優(yōu)惠
      阿里云優(yōu)惠券
      騰訊云優(yōu)惠券
      京東云優(yōu)惠券
      站點(diǎn)信息
      問(wèn)題反饋
      郵箱:[email protected]
      QQ群:637538335
      關(guān)注微信

        <ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>
          国产欧美一区二区精品婷婷 | 久久久激情电影 | 黄色的录像 | 超污动态图 | 草草久久久亚洲黑人AV成人片 | 1024国产 | 亚洲淫香淫色 | 91美女的裸体网站 | 被黑人操| 日韩在线视频一区二区三区 |