bug报告:数据库中已存在名为 'Teacher' 的对象

Nov 28, 2009 at 6:22 PM

 

“/TeacherManager”应用程序中的服务器错误。

数据库中已存在名为 'Teacher' 的对象。

说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。

异常详细信息: System.Data.SqlClient.SqlException: 数据库中已存在名为 'Teacher' 的对象。

源错误:

行 349:        public static Teacher GetByUserName(string username)
行 350:        {
行 351:            return FindOne( CK.K["UserName"] == username );
行 352:        }
行 353:    }


源文件: D:\SchoolWeb\TeacherManager\BLL\Teacher.cs    行: 351

堆栈跟踪:

[SqlException (0x80131904): 数据库中已存在名为 'Teacher' 的对象。]
   System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) +1948826
   System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) +4844747
   System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) +194
   System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) +2392
   System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async) +192
   System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe) +317
   System.Data.SqlClient.SqlCommand.ExecuteNonQuery() +137
   Lephone.Data.SqlEntry.<>c__DisplayClass13.<ExecuteNonQuery>b__12() +94
   Lephone.Data.SqlEntry.DataProvider.NewConnection(CallbackVoidHandler callback) +94
   Lephone.Data.SqlEntry.DataProvider.UsingConnection(CallbackVoidHandler callback) +44
   Lephone.Data.SqlEntry.DataProvider.ExecuteNonQuery(SqlStatement Sql) +79
   Lephone.Data.DbContext.Create(Type dbObjectType) +51
   Lephone.Data.<>c__DisplayClass20.<InnerTryCreateTable>b__1e() +43
   Lephone.Data.DbContext.IfUsingTransaction(Boolean isUsing, CallbackVoidHandler callback) +37
   Lephone.Data.DbContext.InnerTryCreateTable(Type dbObjectType, ObjectInfo oi) +182
   Lephone.Data.DbContext.TryCreateTable(Type dbObjectType) +115
   Lephone.Data.DbContext.DataLoadDirect(IProcessor ip, Type returnType, Type dbObjectType, SqlStatement sql, Boolean useIndex) +66
   Lephone.Data.DbContext.DataLoad(IProcessor ip, Type dbObjectType, FromClause from, WhereCondition iwc, OrderBy oc, Range lc, Boolean isDistinct) +88
   Lephone.Data.DbContext.FillCollection(IList list, Type dbObjectType, WhereCondition iwc, OrderBy oc, Range lc, Boolean isDistinct) +46
   Lephone.Data.DbContext.GetObject(Type t, WhereCondition c, OrderBy ob, Range r) +49
   Lephone.Data.DbContext.GetObject(WhereCondition c) +70
   Lephone.Data.DbEntry.GetObject(WhereCondition c) +56
   Lephone.Data.Definition.DbObjectModelBase`2.FindOne(WhereCondition con) +45
   TeacherManager.BLL.Teacher.GetByUserName(String username) in D:\SchoolWeb\TeacherManager\BLL\Teacher.cs:351
   TeacherCePingItem.get_CurTeacher() in d:\SchoolWeb\TeacherManager\TeacherManager\TeacherCePingItem.aspx.cs:41
   TeacherCePingItem.BindData() in d:\SchoolWeb\TeacherManager\TeacherManager\TeacherCePingItem.aspx.cs:75
   TeacherCePingItem.Page_Load(Object sender, EventArgs e) in d:\SchoolWeb\TeacherManager\TeacherManager\TeacherCePingItem.aspx.cs:30
   System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
   System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
   System.Web.UI.Control.OnLoad(EventArgs e) +99
   System.Web.UI.Control.LoadRecursive() +50
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +627



版本信息: Microsoft .NET Framework 版本:2.0.50727.3053; ASP.NET 版本:2.0.50727.3053

<!-- [SqlException]: 数据库中已存在名为 'Teacher' 的对象。 在 System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) 在 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) 在 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) 在 System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) 在 System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async) 在 System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe) 在 System.Data.SqlClient.SqlCommand.ExecuteNonQuery() 在 Lephone.Data.SqlEntry.DataProvider.<>c__DisplayClass13.<ExecuteNonQuery>b__12() 在 Lephone.Data.SqlEntry.DataProvider.NewConnection(CallbackVoidHandler callback) 在 Lephone.Data.SqlEntry.DataProvider.UsingConnection(CallbackVoidHandler callback) 在 Lephone.Data.SqlEntry.DataProvider.ExecuteNonQuery(SqlStatement Sql) 在 Lephone.Data.DbContext.Create(Type dbObjectType) 在 Lephone.Data.DbContext.<>c__DisplayClass20.<InnerTryCreateTable>b__1e() 在 Lephone.Data.DbContext.IfUsingTransaction(Boolean isUsing, CallbackVoidHandler callback) 在 Lephone.Data.DbContext.InnerTryCreateTable(Type dbObjectType, ObjectInfo oi) 在 Lephone.Data.DbContext.TryCreateTable(Type dbObjectType) 在 Lephone.Data.DbContext.DataLoadDirect(IProcessor ip, Type returnType, Type dbObjectType, SqlStatement sql, Boolean useIndex) 在 Lephone.Data.DbContext.DataLoad(IProcessor ip, Type dbObjectType, FromClause from, WhereCondition iwc, OrderBy oc, Range lc, Boolean isDistinct) 在 Lephone.Data.DbContext.FillCollection(IList list, Type dbObjectType, WhereCondition iwc, OrderBy oc, Range lc, Boolean isDistinct) 在 Lephone.Data.DbContext.GetObject(Type t, WhereCondition c, OrderBy ob, Range r) 在 Lephone.Data.DbContext.GetObject[T](WhereCondition c) 在 Lephone.Data.DbEntry.GetObject[T](WhereCondition c) 在 Lephone.Data.Definition.DbObjectModelBase`2.FindOne(WhereCondition con) 在 TeacherManager.BLL.Teacher.GetByUserName(String username) 位置 D:\SchoolWeb\TeacherManager\BLL\Teacher.cs:行号 351 在 TeacherCePingItem.get_CurTeacher() 位置 d:\SchoolWeb\TeacherManager\TeacherManager\TeacherCePingItem.aspx.cs:行号 41 在 TeacherCePingItem.BindData() 位置 d:\SchoolWeb\TeacherManager\TeacherManager\TeacherCePingItem.aspx.cs:行号 75 在 TeacherCePingItem.Page_Load(Object sender, EventArgs e) 位置 d:\SchoolWeb\TeacherManager\TeacherManager\TeacherCePingItem.aspx.cs:行号 30 在 System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) 在 System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) 在 System.Web.UI.Control.OnLoad(EventArgs e) 在 System.Web.UI.Control.LoadRecursive() 在 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) [HttpUnhandledException]: 引发类型为“System.Web.HttpUnhandledException”的异常。 在 System.Web.UI.Page.HandleError(Exception e) 在 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) 在 System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) 在 System.Web.UI.Page.ProcessRequest() 在 System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context) 在 System.Web.UI.Page.ProcessRequest(HttpContext context) 在 ASP.teachercepingitem_aspx.ProcessRequest(HttpContext context) 位置 d:\SchoolWeb\Temp\teachermanager\a37e6717\4f837500\App_Web_hxfqtiuk.16.cs:行号 0 在 System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 在 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) -->
Coordinator
Nov 29, 2009 at 2:46 AM

单从trace信息,看不太出来造成这个问题的原因,请提供一个可以重现此bug的最小程序。

谢谢。

Coordinator
Nov 29, 2009 at 3:07 AM

另外,DbEntry的AutoCreateTable基于启动时对于数据库表的检测进行,如果启动后有新表,则DbEntry不会知道。在两台不同的Web Server上如果都启动了AutoCreateTable功能,也有可能造成这个问题,所以不建议生产环境使用AutoCreateTable功能。

 

Nov 29, 2009 at 3:20 AM
 C#:   lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。   线程处理(C# 编程指南) 这节讨论了线程处理。   lock 调用块开始位置的 Enter 和块结束位置的 Exit。 TryCreateTable以及ObjectInfo的创建都是应用程序级,,,可能要用应用程序级的Lock, 楼主说的,在两台不同的Web Server上如果都启动了AutoCreateTable功能.....原理上也差不多,,,是个同步与互斥的问题,,,,跟程序运行时间间隔感觉有关系。 先用着,,过段时间,我再想办法弄个最小重现此bug的小程序。 我只是感觉这问题重要,所以先提一下,,楼主不必急于修复,,可能并不影响一般的使用。。
Coordinator
Nov 29, 2009 at 6:12 AM

ObjectInfo是有线程同步的,TryCreateTable可能也需要,我会检查一下的。

不过,两台Web Server的问题跟线程同步没关系。两台Web Server的问题在于,每台服务器都在启动时读取了数据表名,然后保存在各自的内存里,然后在用到了这个表时,就去内存里检查是否有这个表,如果内存里显示没有,则生成Create语句,如果一台Web Server先生成了Teacher表,另一台Web Server并不知道,即使是几个小时以后才在另一台Web Server上调用此表,也一样会生成Create语句的。

Coordinator
Nov 29, 2009 at 9:01 AM

考虑了一下,我觉得TryCreateTable不需要加线程同步,它只应该用于开发以及简单测试。生产环境和压力测试环境都不应该使用此功能。

就像上面说的多台Web Server之间的问题,用线程同步根本无法解决,它需要类似服务器间Session同步的功能。当然,也可以每一次有SQL调用时就去调用数据库检查是否有此表存在。不过,不管是Session同步还是每次检测数据库,只是为了自动创建表,其开销对于生产环境是不太能接受的。

另外,生产环境和压力测试环境,也不应该依赖自动创建表机制,而应该有确定的数据库结构以及一些初始数据。以我的经验来说,应该有一个项目叫做InitDatabase,进行数据库的初始化工作,类似Samples中Orm里的InitDatabase的做法。

Coordinator
Nov 29, 2009 at 9:04 AM

如果你遇到的这个Bug是在一台Web Server时进行开发时就可以重现的,希望你能提供一个可重现的代码和重现步骤,谢谢。

 

Nov 29, 2009 at 2:55 PM

我个人比较喜欢DropAndCreateTable方法~