我正在构建一个MVC 5 Web应用程序,我正在使用实体框架6,我有MS SQL Server 2008 R2作为我的数据库。我使用连接池来确保尽可能快地获得数据库操作的连接。我在Web.config中的连接字符串如下
<add name="MyConnectionPoolConnectionString" connectionString="Data Source=MyHOST;Initial Catalog=TEST_DB;User Id=sa;Password=password1; Min Pool Size=10;MultipleActiveResultSets=True;" providerName="System.Data.SqlClient" />
我注意到从连接池获得连接非常快,即几十到几百毫秒
但是,我还注意到关闭连接(在连接池中意味着连接返回到池)需要相当长的时间(即平均在2000ms和5000ms之间(2 - 5秒)) )。
以下是我的分析日志的摘录
打开连接所需的时间
2015-02-18 21:06:55,497 Opened connection at 18/02/2015 21:06:55 92.65 ms
关闭/返回连接所需的时间
Closed connection at 18/02/2015 21:07:01 2543.06 ms
请注意,打开连接需要92毫秒,关闭连接需要2500毫秒。 顺便说一句,这些统计数据是我自己的EF框架提供的,即通过在EF上下文中设置数据库道具的Log属性,即
MyTestAppDbContext.Database.Log = Logger.Debug;
我不明白为什么从连接池获取连接速度如此之快,但是EF需要很长时间才能将连接返回到池中(即关闭连接),更重要的是如何加快连接速度发布/关闭连接
这对我来说非常重要,因为Web应用程序需要非常敏感,因为我必须为每个请求创建EF Dbcontext,如果EF为关闭/释放连接增加额外的2-5秒开销,它降低了应用的响应能力。
MyTestAppDbContext.cs
public partial class MyTestAppDbContext : DbContext
{
public ILogger Logger { get; set; }
static MyTestAppDbContext()
{
System.Data.Entity.Database.SetInitializer<MyTestAppDbContext>(null);
}
public MyTestAppDbContext(ILogger logger)
: base("Name=MyConnectionPoolConnectionString")
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
Logger = logger;
this.Database.Log = Logger.Debug;
}
public override int SaveChanges()
{
Exception entityFrameworkExceptions = null;
String exMsg = "";
int result = 0;
try
{
if (this.ChangeTracker.HasChanges())
{
// Get all Added/Deleted/Modified entities (not Unmodified or Detached)
foreach (var ent in this.ChangeTracker.Entries().Where(p => p.State == EntityState.Added || p.State == EntityState.Deleted || p.State == EntityState.Modified))
{
// For each changed record, log the activity performed
Logger.Debug("Detected Changes");
}
result = base.SaveChanges();
}
}
catch (DbEntityValidationException dbEx)
{
entityFrameworkExceptions = dbEx;
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
//System.Diagnostics.Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
exMsg += String.Format("\nProperty: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
Logger.Debug(String.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage));
}
}
}
catch (DbUpdateException dbEx)
{
entityFrameworkExceptions = dbEx;
Logger.Debug(String.Format("Exception Message: {0}", dbEx.Message));
Logger.Debug(String.Format("InnerException: {0}", dbEx.InnerException));
Logger.Debug(String.Format("StackTrace: {0}", dbEx.StackTrace));
Logger.Debug(String.Format("Call Stack: {0}", CommonUtils.GetCallStackAsString()));
}
catch (Exception ex)
{
entityFrameworkExceptions = ex;
Logger.Debug(String.Format("Exception Message: {0}", ex.Message));
Logger.Debug(String.Format("InnerException: {0}", ex.InnerException));
Logger.Debug(String.Format("StackTrace: {0}", ex.StackTrace));
Logger.Debug(String.Format("Call Stack: {0}", CommonUtils.GetCallStackAsString()));
}
if (entityFrameworkExceptions != null)
{
exMsg = exMsg + "\n" + entityFrameworkExceptions.Message + @"\n" + entityFrameworkExceptions.StackTrace + @"\n" + entityFrameworkExceptions.InnerException;
entityFrameworkExceptions = new HttpException(500, @"Exception applying changes in PaceDBContext (i.e. Entity Framework)\n" + exMsg+"\n"+CommonUtils.GetCallStackAsString());
throw entityFrameworkExceptions;
}
return result;
}
}
IUnitOfWork.cs
public interface IUnitOfWork /*: IDisposable*/
{
MyTestAppDbContext MyTestAppDbContext { get; set; }
Exception Save();
}
UnitOfWork.cs
public class UnitOfWork : IUnitOfWork, IDisposable
{
private bool disposed = false;
public MyTestAppDbContext MyTestAppDbContext {get; set;}
public ILogger Logger { get; set; }
public Exception Save()
{
Exception entityFrameworkExceptions = null;
String exMsg = "";//, callStackAsString = "";
try
{
System.Diagnostics.Trace.TraceInformation("Saving Db Changes in UnitOfWork");
MyTestAppDbContext.SaveChanges();
System.Diagnostics.Trace.TraceInformation("Finished saving Db Changes in UnitOfWork");
}
catch (DbEntityValidationException dbEx)
{
entityFrameworkExceptions = dbEx;
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
exMsg += String.Format("\nProperty: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
Logger.Debug(String.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage));
}
}
}
catch (DbUpdateException dbEx)
{
entityFrameworkExceptions = dbEx;
this.LogException(dbEx);
}
catch (Exception ex)
{
entityFrameworkExceptions = ex;
this.LogException(ex);
}
if (entityFrameworkExceptions != null)
{
exMsg = "\n" + entityFrameworkExceptions.Message + @"\n" + entityFrameworkExceptions.StackTrace + @"\n" + entityFrameworkExceptions.InnerException+"\n"+CommonUtils.GetCallStackAsString();
entityFrameworkExceptions = new HttpException(500, @"Exception applying changes in PaceDBContext (i.e. Entity Framework)\n" + exMsg);
throw entityFrameworkExceptions;
}
return entityFrameworkExceptions;
}
protected virtual void Dispose(bool disposing)
{
this.Save();
if (!this.disposed)
{
if (disposing)
{
MyTestAppDbContext.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void LogException(Exception ex){
Logger.Debug(String.Format("Exception Message: {0}", ex.Message));
Logger.Debug(String.Format("InnerException: {0}", ex.InnerException));
Logger.Debug(String.Format("StackTrace: {0}", ex.StackTrace));
}
}
UserRepository.cs
public class UserRepository : IUserRepository
{
public IUnitOfWork UnitOfWork { get; private set; }
public UserRepository(IUnitOfWork unitOfWork)
{
this.UnitOfWork = unitOfWork;
}
public Users GetUserByUserId(string userId)
{
if (!String.IsNullOrEmpty(userId)){
var user = from u in UnitOfWork.MyTestAppDbContext.Users
where u.UserId.Trim().Equals(userId.Trim())
select u;
return user.SingleOrDefault();
}
return null;
}
public string GetUserFullName(string userId)
{
string fullname = null;
if (!String.IsNullOrEmpty(userId))
{
var user = (from u in UnitOfWork.MyTestAppDbContext.Users
where u.UserId.Trim().Equals(userId.Trim())
select u).SingleOrDefault();
if (user != null)
{
if (!String.IsNullOrEmpty(user.FirstName))
fullname += user.FirstName + " ";
if (!String.IsNullOrEmpty(user.LastName))
fullname += user.LastName;
}
}
return fullname;
}
public long GetUserGroupId(string userId)
{
if (!String.IsNullOrEmpty(userId))
{
var user = (from u in UnitOfWork.MyTestAppDbContext.Users
where u.UserId.Trim().Equals(userId.Trim())
select u).SingleOrDefault();
if (user != null)
return user.UserGroupId;
}
return -1;
}
}
由于