我在c#中有一个数据表,每隔几毫秒就会获得一个新行。我希望这个数据表每隔10秒在SQL服务器中进行批量复制,但是我得到一个例外“收集被修改;枚举操作可能无法执行”所以我使用锁来绕过该错误。锁是一种好方法还是有更好的选择呢?
lock (testdatatable.Rows.SyncRoot)
{
s.WriteToServer(testdatatable);
}
答案 0 :(得分:0)
我不是C#guru,但是喜欢玩任何与SQL服务器相关的东西。
对我来说,您将ADO数据表锁定在内存中。由于您没有发布其余的代码,我无法判断它是否与SQL Server表相关联。我打赌你是。
该消息表明未说明的数据已被修改。
是否有一个批量复制流程踩到另一个?
查看ConcernedOfTunbridgeWells的条目以获得良好的编码风格 -
Best Practices for uploading files to database
我的主要问题是你为什么每10秒做一次?
在那个频率上,有些事情浮现在脑海中。
1 - 您使用的是没有索引和完整性的临时表吗?如果数据大小很大,则重建索引需要时间。
2 - 底层的SqlBulkCopy类用于锁定是什么。 TABLOCK可能会以此速率导致阻塞。
如果你有sysadmin访问数据库的权限,这里有一些简单的命令来查看锁。
--
-- Locked object details
--
-- Old school technique
EXEC sp_lock
GO
-- Lock details
SELECT
resource_type, resource_associated_entity_id,
request_status, request_mode,request_session_id,
resource_description
FROM sys.dm_tran_locks
WHERE resource_database_id = DB_ID('AdventureWorks2012')
GO
-- Page/Key details
SELECT object_name(object_id) as object_nm, *
FROM sys.partitions
WHERE hobt_id = 72057594047037440
GO
-- Object details
SELECT object_name(1266103551)
GO
批量复制的技术下一页代码。
http://technet.microsoft.com/en-us/library/ms130809.aspx
TABLOCK:在批量复制操作期间获取表级锁。此选项可显着提高性能,因为仅在批量复制操作期间保持锁定可减少表上的锁争用。如果表没有索引并且指定了TABLOCK,则可以同时由多个客户端加载表。默认情况下,锁定行为由批量加载时的表选项表锁定确定。
总之,尝试增加BULK COPY操作之间的时间。查看错误是否消失。
答案 1 :(得分:0)
也许这个问题应该用“c#”标记而不是sql?
您的问题(我认为)与您修改集合有关,对吧? 这是一个普遍的问题,我认为你可以在这里找到解决方案:
"Collection was modified..." Issue
如果没有,那么我们必须查看您的代码以进行更多调查。
答案 2 :(得分:0)
这个问题与:
无关这里的根本问题是批量复制将枚举集合。当这种情况发生时,你正在改变这个系列。
就是这样。
.NET中的几乎所有枚举器实现都将与它所枚举的集合合作,如果集合在枚举器仍处于活动状态时发生更改,则枚举器将停止工作。
示例:
问题:
如果您在拨打电话或与该人通话时从列表中删除某人,该怎么办?我应该挂断电话吗?
如果底层集合在枚举时发生更改,则大多数.NET集合枚举器将停止工作,具有该精确异常。
“修复”这个问题的常用方法是复制该集合。
基本上,不要这样做:
foreach (var x in y)
你这样做:
foreach (var x in y.ToArray())
.ToArray()
调用将复制到一个单独的数组中,然后整个for循环将对其进行枚举。如果y
平均时间发生变化,则无关紧要。
但是,在你的情况下,你离实际的for循环或类似的东西还不远。
我会确保此处的DataTable
在您将其批量复制到数据库时不会发生变化。
锁是不正确的,至少不是自己做的,因为任何其他不锁定的代码当然会完全忽略锁。 lock
语句不会神奇地阻止其他线程更改实例,它只是对实例锁定其他尝试锁定的线程也会停止这样做。如果在修改对象之前没有其他线程尝试锁定该对象,则锁定基本上什么也不做。