将数据加载到 SQL Server 时出现 C# 多线程问题
本文关键字:多线程 问题 Server 数据 加载 SQL | 更新日期: 2023-09-27 17:56:38
我有一个大约 7030 个项目的列表。我将列表中的项目保存到 SQL 服务器中的表中。我想,我可以使用多线程来加快该过程,它确实出现了一个问题。
上传到数据库的项目数没有变化,但是当我在运行代码后查询表中的记录数时,它总是不同的,比如一次它将上传 6925,下一次上传 6831 等。我不明白为什么会发生这种情况。
在我获取数据的课堂上
void DatabaseUploadMultiThreading()
{
DateTime dtUpload = Program.UploadDate();
int numThread = 8;
int splitNum = _holdingList.Count / numThread;
int leftOver = _holdingList.Count - (splitNum * (numThread - 1));
DatabaseWriter[] dbArray = new DatabaseWriter[numThread];
List<Holding>[] holdingArray = new List<Holding>[numThread];
Task[] taskDB = new Task[numThread];
for (int i = 0; i < holdingArray.Length; i++)
{
dbArray[i] = new DatabaseWriter(i + 1, dtUpload);
if (i == (numThread - 1))
holdingArray[i] = _holdingList.GetRange(i * splitNum, leftOver);
else
holdingArray[i] = _holdingList.GetRange(i * splitNum, splitNum);
}
for (int i = 0; i < taskDB.Length; i++)
taskDB[i] = Task.Factory.StartNew(dbArray[i].UploadHoldings, holdingArray[i]);
try
{
Task.WaitAll(taskDB); // wait for all the threads to complete
}
catch (AggregateException ex)
{
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
}
}
数据库编写器类狙击手
class DatabaseWriter : IDisposable
{
#region variable declaration
private SqlConnection _connection;
private SqlCommand _command;
private static readonly string _connectionString = "myConnectionString";
public void UploadHoldings(object objHoldingList)
{
List<Holding> holdingList = (List<Holding>)objHoldingList;
using (_connection = new SqlConnection(_connectionString))
{
_connection.Open();
DataReImported(_dtUpload);
for (int i = 0; i < holdingList.Count; i++)
{
string cmdText = "INSERT INTO HOLDINGS([FUND_CD], [SEDOLCHK], [NOMINAL], [CURR], [PRICE], [DATEU]) " +
"VALUES(@fundcode, @sedol, @nominal, @curr, @price, @dtUpload)";
_command = new SqlCommand(cmdText, _connection);
_command.Parameters.Add("@fundCode", SqlDbType.VarChar).Value = holdingList[i].FundCode;
_command.Parameters.Add("@sedol", SqlDbType.VarChar).Value = holdingList[i].IdSedol;
_command.Parameters.Add("@nominal", SqlDbType.Decimal).Value = holdingList[i].Nominal;
_command.Parameters.Add("@curr", SqlDbType.VarChar).Value = holdingList[i].Currency;
_command.Parameters.Add("@price", SqlDbType.Decimal).Value = holdingList[i].Price;
_command.Parameters.Add("@dtUpload", SqlDbType.Date).Value = _dtUpload;
_command.ExecuteNonQuery();
Console.WriteLine("Thread Number:" + _threadNum + " Security Number uploaded: " + i + " of " + holdingList.Count);
}
_connection.Close();
}
}
}
我建议这不是使用多个任务的最佳位置。如上所示的代码效率有点低,在许多情况下,将其拆分为 Task 对象并并行运行它们只会使它们彼此重叠并减慢您的速度或导致其中一个无法执行。就像三个傀儡同时试图冲进一扇门一样。
按照上面其他回答者的建议进行基本的、明显的优化,即只创建一次 SqlCommand,并在循环中执行绝对最小值(或者尝试批量加载方法)。并检查 ExecuteNonQuery 返回的值以验证写入的记录数。