使用C#循环反复多次连接SQL数据库,出现“内部连接致命错误”的问题,怎么解决?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用C#循环反复多次连接SQL数据库,出现“内部连接致命错误”的问题,怎么解决?相关的知识,希望对你有一定的参考价值。
连接数据库的方法getcon():
public static SqlConnection getcon()
if (My_con == null)
My_con = new SqlConnection(M_str_sqlcon);
My_con.Open();
else if (My_con.State == ConnectionState.Broken)
My_con.Close();
My_con.Open();
else if (My_con.State == ConnectionState.Closed)
My_con.Open();
return My_con;
建立dataset的方法getDataSet:
public DataSet getDataSet(string SQLstr, string tableName)
while (My_con.State != ConnectionState.Open)
getcon();
SqlDataAdapter SQLda = new SqlDataAdapter(SQLstr, My_con);
DataSet My_DataSet = new DataSet();
SQLda.Fill(My_DataSet, tableName);
My_DataSet.Dispose();
//con_close();
return My_DataSet;
我在计时器timer中多次反复调用getDataSet方法,开始时一切正常,大约40多分钟后出现“内部连接致命错误”的问题;如果每次连接SQL数据库后都关闭连接,则运行十分中后会出现“ExecuteReader 要求已打开且可用的连接。连接的当前状态为已打开”的问题。怎么解决啊???
SqlDataAdapter SQLda = new SqlDataAdapter(SQLstr, My_con);
DataSet My_DataSet = new DataSet();
SQLda.Fill(My_DataSet, tableName); 参考技术B 不建议Connection设置成static,这样反而会降低性能,建议改成using的形式,每次用到再new。追问
请问具体怎么写?能详细讲讲么?
追答去掉你的My_con变量,在每个需要的地方
using(SqlConnection conn=new SqlConnection(连接字符串))
Try
conn.Open();
XX其他语句
conn.Close();
Catch()
xxx
使用 for 循环将多条记录插入 SQL Server 数据库
【中文标题】使用 for 循环将多条记录插入 SQL Server 数据库【英文标题】:Inserting Multiple Records into SQL Server database using for loop 【发布时间】:2016-08-17 09:20:36 【问题描述】:我正在使用 C# 编写一个 Windows 窗体项目。我正在尝试将多个记录从数组中插入 SQL Server 数据库。
进入第一行后出现异常
@UserID 已被声明。变量名称在查询批处理或存储过程中必须是唯一的。
数据库中的主键没有问题,因为UserID
不是主键。
这就是我想要做的。
public static void featuresentry()
SqlConnection connection = new SqlConnection(HandVeinPattern.Properties.Settings.Default.HandVeinPatternConnectionString);
SqlCommand command = new SqlCommand();
connection.Open();
try
command = connection.CreateCommand();
for (int i = 0; i < Details.modelKeyPoints.Size; i++)
command.CommandText = "INSERT INTO FEATURES(UserID, Angle, ClassID, Octave, PointX, PointY, Response, Size) VALUES(@UserID, @Angle, @ClassID, @Octave, @PointX, @PointY, @Response, @Size)";
command.Parameters.AddWithValue("@UserID", Details.ID);
command.Parameters.AddWithValue("@Angle", Convert.ToDouble(Details.modelKeyPoints[i].Angle));
command.Parameters.AddWithValue("@ClassID", Convert.ToDouble(Details.modelKeyPoints[i].ClassId));
command.Parameters.AddWithValue("@Octave", Convert.ToDouble(Details.modelKeyPoints[i].Octave));
command.Parameters.AddWithValue("@PointX", Convert.ToDouble(Details.modelKeyPoints[i].Point.X));
command.Parameters.AddWithValue("@PointY", Convert.ToDouble(Details.modelKeyPoints[i].Point.Y));
command.Parameters.AddWithValue("@Response", Convert.ToDouble(Details.modelKeyPoints[i].Response));
command.Parameters.AddWithValue("@Size", Convert.ToDouble(Details.modelKeyPoints[i].Size));
command.ExecuteNonQuery();
catch (Exception)
throw;
finally
if (connection.State == ConnectionState.Open)
connection.Close();
【问题讨论】:
我认为如果你将command = connection.CreateCommand();
放在你的 for 循环中,它会起作用。问题是你只循环命令参数,所以它试图向你现有的命令添加更多参数,但它们已经在那里了。所以你需要在每个循环中创建一个新命令。
@UnicornoMarley,是的,这就是问题所在。不错的收获,将其发布为答案。
另一种选择是将所有命令和参数创建移到循环之外,只更新值并在循环内执行。这样您就不会不断地创建新的对象实例。
@Unicorno 。谢谢您的帮助。它奏效了。
【参考方案1】:
您需要在循环外添加 Command 参数或在循环内声明 Command。
在第一种情况下,您需要像这样更新每个参数的值:
oleDbCommand1.Parameters["@UserID"].Value = Details.ID;
并在设置新值后执行命令。
【讨论】:
【参考方案2】:如果你将command = connection.CreateCommand();
放在你的 for 循环中,它将起作用。问题是你只循环命令参数,所以它试图向你现有的命令添加更多参数,但它们已经在那里了。所以你需要在每个循环中创建一个新命令。
【讨论】:
【参考方案3】:您应该正确这样做:
在循环外定义参数一次 在每次迭代的循环内定义参数的值 使用using(...) ...
块删除try ... catch ... finally
(using
块将确保在不再需要时正确快速地处理您的课程)
如果您实际上没有处理异常,请停止使用try...catch
- 只需重新抛出它们(没有意义)
试试这个代码:
public static void featuresentry()
string connectionString = HandVeinPattern.Properties.Settings.Default.HandVeinPatternConnectionString;
string insertQuery = "INSERT INTO FEATURES(UserID, Angle, ClassID, Octave, PointX, PointY, Response, Size) VALUES(@UserID, @Angle, @ClassID, @Octave, @PointX, @PointY, @Response, @Size)";
using (SqlConnection connection = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(insertQuery, connection))
// define your parameters ONCE outside the loop, and use EXPLICIT typing
command.Parameters.Add("@UserID", SqlDbType.Int);
command.Parameters.Add("@Angle", SqlDbType.Double);
command.Parameters.Add("@ClassID", SqlDbType.Double);
command.Parameters.Add("@Octave", SqlDbType.Double);
command.Parameters.Add("@PointX", SqlDbType.Double);
command.Parameters.Add("@PointY", SqlDbType.Double);
command.Parameters.Add("@Response", SqlDbType.Double);
command.Parameters.Add("@Size", SqlDbType.Double);
connection.Open();
for (int i = 0; i < Details.modelKeyPoints.Size; i++)
// now just SET the values
command.Parameters["@UserID"].Value = Details.ID;
command.Parameters["@Angle"].Value = Convert.ToDouble(Details.modelKeyPoints[i].Angle);
command.Parameters["@ClassID"].Value = Convert.ToDouble(Details.modelKeyPoints[i].ClassId);
command.Parameters["@Octave"].Value = Convert.ToDouble(Details.modelKeyPoints[i].Octave);
command.Parameters["@PointX"].Value = Convert.ToDouble(Details.modelKeyPoints[i].Point.X);
command.Parameters["@PointY"].Value = Convert.ToDouble(Details.modelKeyPoints[i].Point.Y);
command.Parameters["@Response"].Value = Convert.ToDouble(Details.modelKeyPoints[i].Response);
command.Parameters["@Size"].Value = Convert.ToDouble(Details.modelKeyPoints[i].Size);
command.ExecuteNonQuery();
【讨论】:
或者更好的是,使用表值参数并只执行一条语句... @ZoharPeled 很遗憾你没有按照这些思路提供答案!【参考方案4】:为了获得最大的性能,您可以考虑使用BulkInsert。这可以确保您的插入尽可能快地完成,因为任何发出的查询都有一些开销(大查询通常比许多小查询执行得更快)。它应该如下所示:
1) 从here定义AsDataTable扩展方法:
public static DataTable AsDataTable<T>(this IEnumerable<T> data)
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
var table = new DataTable();
foreach (PropertyDescriptor prop in properties)
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (T item in data)
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
return table;
2) 像这样执行实际的 BulkInsert(未测试):
using (SqlConnection connection = new SqlConnection(connectionString))
connection.Open();
SqlTransaction transaction = connection.BeginTransaction();
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
bulkCopy.BatchSize = 100;
bulkCopy.DestinationTableName = "dbo.FEATURES";
try
// define mappings for columns, as property names / generated data table column names
// is different from destination table column name
bulkCopy.ColumnMappings.Add("ID","UserID");
bulkCopy.ColumnMappings.Add("Angle","Angle");
// the other mappings come here
bulkCopy.WriteToServer(Details.modelKeyPoints.AsDataTable());
catch (Exception)
transaction.Rollback();
connection.Close();
transaction.Commit();
当然,如果使用convention over configuration(对象属性名称将与目标表列名称完全匹配),则不需要映射。
【讨论】:
【参考方案5】:您可以通过将数据作为 xml 字符串发送并在 sql 中的存储过程中转换为表来完成此操作。例如: 假设我要发送多行以在 sql 表中添加/更新,那么步骤如下:
使用以下方法将您的类或类列表转换为 xml 字符串:
public static string SerializeObjectToXmlString(object value)
var emptyNamepsaces = new XmlSerializerNamespaces(new[]
XmlQualifiedName.Empty );
var serializer = new XmlSerializer(value.GetType());
var settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, settings))
serializer.Serialize(writer, value, emptyNamepsaces);
return stream.ToString();
现在在向数据库发送数据时将您的类对象转换为 xml 字符串(这里我在我的代码中使用实体框架,你也可以不使用它):
bool AddUpdateData(List<MyClass> data)
bool returnResult = false;
string datatXml = Helper.SerializeObjectToXmlString(data);
var sqlparam = new List<SqlParameter>()
new SqlParameter() ParameterName = "dataXml", Value = datatXml
;
var result = this.myEntity.Repository<SQL_StoredProc_ComplexType>().ExecuteStoredProc("SQL_StoredProc", sqlparam);
if (result != null && result.Count() > 0)
returnResult = result[0].Status == 1 ? true : false;
return returnResult;
现在你的 SQL 代码:
3.1 声明一个表变量:
DECLARE @tableVariableName TABLE
(
ID INT, Name VARCHAR(20)
)
3.2 将您的 xml 字符串插入到表变量中
INSERT INTO @tableVariableName
SELECT
Finaldata.R.value ('(ID/text())[1]', 'INT') AS ID,
Finaldata.R.value ('(Name/text())[1]', 'VARCHAR(20)') AS Name
FROM @MyInputXmlString.nodes ('//ArrayMyClass/MyClass') AS Finaldata (R)
3.3 最后将这个表值插入到你的sql表中
INSERT INTO MyTable (ID, Name)
SELECT ID, Name
FROM @tableVariableName
这将节省您使用 for 循环一次又一次地访问数据库的工作。
希望对你有帮助
【讨论】:
以上是关于使用C#循环反复多次连接SQL数据库,出现“内部连接致命错误”的问题,怎么解决?的主要内容,如果未能解决你的问题,请参考以下文章
运行 Access Query 时反复弹出不需要的 SQL Server 登录对话框