概述
我已经工作了很长时间,试图找到一个解决我的特定情况的帖子,但是已经空了。我正在尝试创建一个C#.NET控制台应用程序,该应用程序将解析具有多个数据库还原定义的XML文件,然后使用SQL管理对象并行启动这些还原。每次还原后,用户可以指定他们希望针对新还原的数据库运行的零到多个SQL文件。每当我并行尝试这些作业中的4个以上时,处理针对数据库执行SQL文件的静态方法会在针对本地创建的ServerConnection调用ExecuteNonQuery()方法时产生阻塞。我是否错误地实施了这个?关于如何使这项工作的任何建议?
尝试解决方案
在上述两种方法中,我都提到了两种静态方法:
致电代码
Parallel.ForEach(restores.Restore,
//new ParallelOptions {MaxDegreeOfParallelism = 4},
restore =>
{
//Grab copies of the backup information
string backup = restore.Backup;
string server = restore.Server;
string database = restore.Database;
string[] patchFiles = restore.PatchFiles;
//Begin by restoring the database from the backup file
RestoreDatabaseFromBackup(backup, server, database);
//Execute each patch file sequentially for the restore defintion
foreach (string patchFile in patchFiles)
{
ExecutePatchFile(patchFile, server, database);
}
});
ExecutePathFile方法
private static void ExecutePatchFile(string patchFile, string server, string database)
{
//Create directory for the log file (if it doesn't already exist)
DirectoryInfo di = CreateLogFileDirectory(server, database);
//Create the log file
StreamWriter sw = File.CreateText(Path.Combine(di.FullName, Path.GetFileNameWithoutExtension(patchFile) + ".log"));
Console.WriteLine("{0} : Beginning execution of {1} for {2} on {3}.", DateTime.Now, patchFile, database, server);
//Verify that 'patchFile' exists and is of the right file extension
if (!File.Exists(patchFile) || Path.GetExtension(patchFile) != ".sql")
{
Console.WriteLine("{0} : Could not execute {1} for {2} on {3}. Invalid SQL file.", DateTime.Now, Path.GetFileName(patchFile), database, server);
sw.WriteLine("{0} : Could not execute {1} for {2} on {3}. Invalid SQL file.", DateTime.Now, Path.GetFileName(patchFile), database, server);
sw.Close();
return;
}
string script = File.ReadAllText(patchFile);
try
{
//Build out connection string
SqlConnectionStringBuilder sb = new SqlConnectionStringBuilder();
sb.DataSource = server;
sb.InitialCatalog = database;
sb.IntegratedSecurity = true;
//Create SqlConnection
SqlConnection sqlCon = new SqlConnection(sb.ToString());
//Set sqlCon to treat exceptions as infomessages
sqlCon.FireInfoMessageEventOnUserErrors = true;
//Create ServerConnection
ServerConnection serverCon = new ServerConnection(sqlCon);
serverCon.InfoMessage += new SqlInfoMessageEventHandler((sender, e) => ConnectionContext_InfoMessage(sender, e, sw));
serverCon.ExecuteNonQuery(script, ExecutionTypes.ContinueOnError);
}
catch (Exception e)
{
throw e;
}
finally
{
sw.Close();
}
}
堆栈跟踪
System.Reflection.TargetInvocationException was unhandled by user code
HResult=-2146232828
Message=Exception has been thrown by the target of an invocation.
Source=BatchDatabaseRestorer
StackTrace:
at BatchDatabaseRestorer.Program.ExecutePatchFile(String patchFile, String server, String database) in c:\Users\zannett\Documents\Visual Studio 2013\Projects\BatchDatabaseRestorer\BatchDatabaseRestorer\Program.cs:line 224
at BatchDatabaseRestorer.Program.<Main>b__0(RestoresRestore restore) in c:\Users\zannett\Documents\Visual Studio 2013\Projects\BatchDatabaseRestorer\BatchDatabaseRestorer\Program.cs:line 83
at System.Threading.Tasks.Parallel.<>c__DisplayClass21`2.<ForEachWorker>b__17(Int32 i)
at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.<ForWorker>b__c()
InnerException: Microsoft.SqlServer.Management.Common.ExecutionFailureException
HResult=-2146233087
Message=Parse error occurred while looking for GO statement. Line 0.
Source=Microsoft.SqlServer.BatchParserClient
StackTrace:
at Microsoft.SqlServer.Management.Common.ExecuteBatch.GetStatements(String sqlCommand)
InnerException: ManagedBatchParser.ParserException
HResult=-2146233088
Message=""
Source=Microsoft.SqlServer.BatchParser
StackTrace:
at ManagedBatchParser.Parser.Parse()
at Microsoft.SqlServer.Management.Common.ExecuteBatch.GetStatements(String sqlCommand)
InnerException:
答案 0 :(得分:0)
我相信当你让它在内部处理解析时,在多个ServerConnection实例上并行调用ExecuteNonQuery()是一个问题。如果我自己沿着GO关键字拆分脚本,然后将命令作为StringCollection(每个可用的覆盖)传递,那么无论并行作业的数量如何,命令都会正常执行。这使我相信Microsoft.SqlServer.BatchParserClient对象或Microsoft.SqlServer.BatchParser对象与ExecuteNonQuery()实现的并行执行不兼容。
答案 1 :(得分:0)
我偶然发现了这个问题,因为我对我提出了同样的异常。我正在通过反射从字符串中解析DateTime
,我很确定TargetInvocationException
正在替换FormatException
,因为我正在使用MethodInfo.Invoke
来调用DateTime的解析方法。用通常的DateTime.Parse
替换后,我得到了FormatException。所以我的字符串格式不正确或者解析器的状态不正确(文化等)。
所以我猜CLR正在用TargetInvocationException
替换调用的函数引发的任何异常。您可以检查字符串并查找要解析的复杂对象,因为它似乎是导致问题的解析器。