为什么我的 SqlConnection 在执行期间进入中断状态?
Why is my SqlConnection entering a broken state during execution?
我有一个简单的控制台应用程序,它正在执行一系列存储过程大约 150,000 次。它的目的是将初始数据库数据导入到数据库的新实例中。
它在工作中运行良好,但在家里我正在尝试使用 Sql Server Express,一切看起来都很好,但恰好在完成 25.76% 时 sql 连接进入断开状态并且生成一个 InvalidOperation Exception,指出连接已断开,无法用于执行下一个命令。
我明白那是什么意思,但我不明白为什么它会坏掉,为什么它在每次尝试 运行 控制台应用程序时都在同一时间发生。
每次都在完成25.76%时进入中断状态,总是在那个地方,并且总是在SQL被执行的同一行。
异常发生时正在执行的行如下:
EXEC [geo].[addUpdateRegion] @countryCode = N'CG', @regionCode = N'08', @regionName = N'Plateaux', @initData = 1
它导致 InvalidOperationException:BeginExecuteNonQuery 需要一个打开且可用的连接。连接的当前状态:断开。"
我很困惑,因为我完全禁用了超时。所以我想知道 SQLExpress 是否对您可以在同一连接上执行的命令数量有限制?
代码如下所示:
using log4net;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace XYZ.SetupData
{
class Program
{
static ILog logger = null;
static string connectionString = null;
static SqlConnection conn = null;
static double lineCount = 1;
static double lineIndex = 1;
static Program()
{
logger = LogManager.GetLogger(typeof(Program));
log4net.Config.XmlConfigurator.Configure();
var connSettings = ConfigurationManager.ConnectionStrings["theDb"];
if (connSettings == null || string.IsNullOrEmpty(connSettings.ConnectionString))
throw new ConfigurationErrorsException("connectionString theDbwas not found or is empty.");
connectionString = connSettings.ConnectionString;
conn = new SqlConnection(connectionString);
conn.Open();
}
static void Main(string[] args)
{
var baseDir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory + "sqlFiles");
var files = baseDir.GetFiles("*.sql", SearchOption.TopDirectoryOnly).Select(file => file.FullName).ToArray();
lineCount = (double)GetTotalFileLines(files);
foreach (var file in files)
{
ExecuteFileLines(file);
}
Console.ReadKey(true);
}
#region Utility
static void WriteProgress(string command)
{
double percent = (lineIndex / lineCount) * 100;
Console.Write("\r Percent Complete: {0}% ", Math.Round(percent, 2));
++lineIndex;
}
static int GetTotalFileLines(params string[] fileNames)
{
int total = 0;
foreach (var fileName in fileNames)
total += (File.ReadLines(fileName).Where(line => !string.IsNullOrEmpty(line) && !line.StartsWith("--")).Count());
return total;
}
static void ExecuteFileLines(string fileName)
{
TryRun(() =>
{
if (string.IsNullOrEmpty(fileName))
throw new ArgumentNullException("fileName");
if (!File.Exists(fileName))
throw new FileNotFoundException("file: " + fileName + " was not found!");
IEnumerable<string> fileLines = File.ReadLines(fileName).Where(line => !string.IsNullOrEmpty(line) && !line.StartsWith("--"));
LogInfo("--Staring Execution: " + fileName);
foreach (var line in fileLines)
{
RunSqlConnection(conn =>
{
LogInfo("RUNNING | " + line);
WriteProgress(line);
try
{
SqlCommand cmd = new SqlCommand(line, conn);
cmd.BeginExecuteNonQuery();
}
catch (Exception ex)
{
int i = 0;
}
});
}
});
}
static void RunSqlConnection(Action<SqlConnection> callBack)
{
try
{
callBack(conn);
}
catch (Exception ex)
{
LogError(ex);
throw ex;
}
}
static void TryRun(Action callBack)
{
try
{
callBack();
}
catch (Exception ex)
{
LogError(ex);
throw ex;
}
}
static void LogError(Exception ex)
{
logger.Error(ex.Message, ex);
Console.WriteLine(ex.ToString());
}
static void LogInfo(string message, params object[] parameters)
{
logger.Info(string.Format(message, parameters));
}
static void LogDebug(string message, params object[] parameters)
{
logger.Debug(string.Format(message, parameters));
}
#endregion
}
}
您应该检查 Sql 服务器版本的比较。
您可能达到了 Sql 速成版每个实例 1 GB 的内存限制。
您正在尝试在多个线程上处理工作。有一个错误是您同时使用同一个连接。这是不允许的。由于这是一个竞争条件,任何事情都可能在内部发生。
我完全不确定您为什么要使用 APM 模式,因为它已经过时了。我认为 PLINQ 加上同步 IO 加上每个工作项一个连接实际上非常适合您的场景。
我有一个简单的控制台应用程序,它正在执行一系列存储过程大约 150,000 次。它的目的是将初始数据库数据导入到数据库的新实例中。
它在工作中运行良好,但在家里我正在尝试使用 Sql Server Express,一切看起来都很好,但恰好在完成 25.76% 时 sql 连接进入断开状态并且生成一个 InvalidOperation Exception,指出连接已断开,无法用于执行下一个命令。
我明白那是什么意思,但我不明白为什么它会坏掉,为什么它在每次尝试 运行 控制台应用程序时都在同一时间发生。
每次都在完成25.76%时进入中断状态,总是在那个地方,并且总是在SQL被执行的同一行。
异常发生时正在执行的行如下:
EXEC [geo].[addUpdateRegion] @countryCode = N'CG', @regionCode = N'08', @regionName = N'Plateaux', @initData = 1
它导致 InvalidOperationException:BeginExecuteNonQuery 需要一个打开且可用的连接。连接的当前状态:断开。"
我很困惑,因为我完全禁用了超时。所以我想知道 SQLExpress 是否对您可以在同一连接上执行的命令数量有限制?
代码如下所示:
using log4net;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace XYZ.SetupData
{
class Program
{
static ILog logger = null;
static string connectionString = null;
static SqlConnection conn = null;
static double lineCount = 1;
static double lineIndex = 1;
static Program()
{
logger = LogManager.GetLogger(typeof(Program));
log4net.Config.XmlConfigurator.Configure();
var connSettings = ConfigurationManager.ConnectionStrings["theDb"];
if (connSettings == null || string.IsNullOrEmpty(connSettings.ConnectionString))
throw new ConfigurationErrorsException("connectionString theDbwas not found or is empty.");
connectionString = connSettings.ConnectionString;
conn = new SqlConnection(connectionString);
conn.Open();
}
static void Main(string[] args)
{
var baseDir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory + "sqlFiles");
var files = baseDir.GetFiles("*.sql", SearchOption.TopDirectoryOnly).Select(file => file.FullName).ToArray();
lineCount = (double)GetTotalFileLines(files);
foreach (var file in files)
{
ExecuteFileLines(file);
}
Console.ReadKey(true);
}
#region Utility
static void WriteProgress(string command)
{
double percent = (lineIndex / lineCount) * 100;
Console.Write("\r Percent Complete: {0}% ", Math.Round(percent, 2));
++lineIndex;
}
static int GetTotalFileLines(params string[] fileNames)
{
int total = 0;
foreach (var fileName in fileNames)
total += (File.ReadLines(fileName).Where(line => !string.IsNullOrEmpty(line) && !line.StartsWith("--")).Count());
return total;
}
static void ExecuteFileLines(string fileName)
{
TryRun(() =>
{
if (string.IsNullOrEmpty(fileName))
throw new ArgumentNullException("fileName");
if (!File.Exists(fileName))
throw new FileNotFoundException("file: " + fileName + " was not found!");
IEnumerable<string> fileLines = File.ReadLines(fileName).Where(line => !string.IsNullOrEmpty(line) && !line.StartsWith("--"));
LogInfo("--Staring Execution: " + fileName);
foreach (var line in fileLines)
{
RunSqlConnection(conn =>
{
LogInfo("RUNNING | " + line);
WriteProgress(line);
try
{
SqlCommand cmd = new SqlCommand(line, conn);
cmd.BeginExecuteNonQuery();
}
catch (Exception ex)
{
int i = 0;
}
});
}
});
}
static void RunSqlConnection(Action<SqlConnection> callBack)
{
try
{
callBack(conn);
}
catch (Exception ex)
{
LogError(ex);
throw ex;
}
}
static void TryRun(Action callBack)
{
try
{
callBack();
}
catch (Exception ex)
{
LogError(ex);
throw ex;
}
}
static void LogError(Exception ex)
{
logger.Error(ex.Message, ex);
Console.WriteLine(ex.ToString());
}
static void LogInfo(string message, params object[] parameters)
{
logger.Info(string.Format(message, parameters));
}
static void LogDebug(string message, params object[] parameters)
{
logger.Debug(string.Format(message, parameters));
}
#endregion
}
}
您应该检查 Sql 服务器版本的比较。
您可能达到了 Sql 速成版每个实例 1 GB 的内存限制。
您正在尝试在多个线程上处理工作。有一个错误是您同时使用同一个连接。这是不允许的。由于这是一个竞争条件,任何事情都可能在内部发生。
我完全不确定您为什么要使用 APM 模式,因为它已经过时了。我认为 PLINQ 加上同步 IO 加上每个工作项一个连接实际上非常适合您的场景。