如何让 TransactionScope 处理大型 sql 事务?
How to get TransactionScope to work on large sql transactions?
我有一个应用程序需要写入 sql 数据库上的 table。 sql 字符串的 IN 语句中使用的 ID 需要分块,因为 IN 中可能有 300k 个 ID,这会溢出 Web 配置中的最大字符串长度。当我尝试使用 200+k ID 测试场景而不是大约 50K ID 时出现此错误:
与当前连接关联的事务已完成但尚未处理。必须先处理事务,然后才能使用连接执行 SQL 语句。
代码如下:
public int? MatchReconDetail(int ReconRuleNameID, List<int> participants, int? matchID, string userID, int FiscalPeriodID)
{
DataContext context = new DataContext();
context.CommandTimeout = 600;
using (TransactionScope transaction = new TransactionScope())
{
Match dbMatch = new Match() { AppUserIDMatchedBy = userID, FiscalPeriodID = FiscalPeriodID, DateCreated = DateTime.Now };
context.Matches.InsertOnSubmit(dbMatch);
context.SubmitChanges();
//string ids = string.Concat(participants.Select(rid => string.Format("{0}, ", rid))).TrimEnd(new char[] { ' ', ',' });
int listCount = participants.Count;
int listChunk = listCount / 1000;
int count = 0;
int countLimit = 1000;
for (int x = 0; x <= listChunk; x++)
{
count = 1000 * x;
countLimit = 1000 * (x + 1);
List<string> chunkList = new List<string>();
for (int i = count; i < countLimit; i++)
{
if (listCount - count < 1000 && listCount - count != 0)
{
int remainder = listCount - count;
for (int r = 0; r < remainder; r++)
{
chunkList.Add(participants[count].ToString());
count++;
}
}
else if (listCount - count >= 1000)
{
chunkList.Add(participants[i].ToString());
}
}
string ids = string.Concat(chunkList.Select(rid => string.Format("{0}, ", rid))).TrimEnd(new char[] { ' ', ',' });
string sqlMatch = string.Format("UPDATE [Cars3]..[ReconDetail] SET [MatchID] = {0} WHERE [ID] IN ({1})", dbMatch.ID, ids);
context.ExecuteCommand(sqlMatch);
}
matchID = dbMatch.ID;
context.udpUpdateSummaryCache(FiscalPeriodID, ReconRuleNameID, false);
transaction.Complete();
}
return matchID;
}
}
我已经阅读了一些建议超时问题的文章,因此我在此函数的顶部添加了 context.CommandTimeout。该错误似乎是在事件触发后大约一分钟后发生的。
如有任何想法,我们将不胜感激。
您也需要设置交易超时时间。不仅是命令。
您可能还必须修改最大事务超时。默认为 10 分钟,可以在 machine.config
文件中更改。
阅读 this blog post 了解更多详情。
我使用以下方法解决了这个问题:
using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0,30,0)))
我有一个应用程序需要写入 sql 数据库上的 table。 sql 字符串的 IN 语句中使用的 ID 需要分块,因为 IN 中可能有 300k 个 ID,这会溢出 Web 配置中的最大字符串长度。当我尝试使用 200+k ID 测试场景而不是大约 50K ID 时出现此错误:
与当前连接关联的事务已完成但尚未处理。必须先处理事务,然后才能使用连接执行 SQL 语句。
代码如下:
public int? MatchReconDetail(int ReconRuleNameID, List<int> participants, int? matchID, string userID, int FiscalPeriodID)
{
DataContext context = new DataContext();
context.CommandTimeout = 600;
using (TransactionScope transaction = new TransactionScope())
{
Match dbMatch = new Match() { AppUserIDMatchedBy = userID, FiscalPeriodID = FiscalPeriodID, DateCreated = DateTime.Now };
context.Matches.InsertOnSubmit(dbMatch);
context.SubmitChanges();
//string ids = string.Concat(participants.Select(rid => string.Format("{0}, ", rid))).TrimEnd(new char[] { ' ', ',' });
int listCount = participants.Count;
int listChunk = listCount / 1000;
int count = 0;
int countLimit = 1000;
for (int x = 0; x <= listChunk; x++)
{
count = 1000 * x;
countLimit = 1000 * (x + 1);
List<string> chunkList = new List<string>();
for (int i = count; i < countLimit; i++)
{
if (listCount - count < 1000 && listCount - count != 0)
{
int remainder = listCount - count;
for (int r = 0; r < remainder; r++)
{
chunkList.Add(participants[count].ToString());
count++;
}
}
else if (listCount - count >= 1000)
{
chunkList.Add(participants[i].ToString());
}
}
string ids = string.Concat(chunkList.Select(rid => string.Format("{0}, ", rid))).TrimEnd(new char[] { ' ', ',' });
string sqlMatch = string.Format("UPDATE [Cars3]..[ReconDetail] SET [MatchID] = {0} WHERE [ID] IN ({1})", dbMatch.ID, ids);
context.ExecuteCommand(sqlMatch);
}
matchID = dbMatch.ID;
context.udpUpdateSummaryCache(FiscalPeriodID, ReconRuleNameID, false);
transaction.Complete();
}
return matchID;
}
}
我已经阅读了一些建议超时问题的文章,因此我在此函数的顶部添加了 context.CommandTimeout。该错误似乎是在事件触发后大约一分钟后发生的。
如有任何想法,我们将不胜感激。
您也需要设置交易超时时间。不仅是命令。
您可能还必须修改最大事务超时。默认为 10 分钟,可以在 machine.config
文件中更改。
阅读 this blog post 了解更多详情。
我使用以下方法解决了这个问题:
using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0,30,0)))