多线程bug之同时插入数据库哭好几条相同数据。

WenJunGG
  • 6

正常情况下,插入数据就是没有问题,
偶尔会出现,同时往数据库插入了好几条相同数据,十分尴尬。

            foreach (var item in productDict)
            {
                Task.Factory.StartNew(() =>
                {
                    LogDataAccess.AddOrderRecord(userId, orderId, item.Item1.ToString(), item.Item2, OrderRecordType.Original, DateTimeOffset.Now);
                });
            }
            
            

网上虽然也找了,但是未层找到原因,请大神们相助,感激不尽!

回复
阅读 3.3k
5 个回答

你 .Net的版本是哪个?.Net 4.5及以后不会有这个问题,.Net 4.0应该会有闭包问题,

foreach (var item in productDict)
            {
                var localItem = item;
                Task.Factory.StartNew(() =>
                {
                    LogDataAccess.AddOrderRecord(userId, orderId, localItem.Item1.ToString(), localItem.Item2, OrderRecordType.Original, DateTimeOffset.Now);
                });
            }

1楼的答案是正确的。

            foreach (var item in productDict)
            {
                var localItem = item;
                Task.Factory.StartNew(() =>
                {
                    LogDataAccess.AddOrderRecord(userId, orderId, localItem.Item1.ToString(), localItem.Item2, OrderRecordType.Original, DateTimeOffset.Now);
                });
            }

在foreach中重新定义一个变量与不定义的区别在于。不定义一个新的变量,多个任务可能同时进行,会共享同一个item,所以就会出现插入相同数据的问题。

其实,这不是妥善的方法,即便使用并行,仍然需要多次访问数据库。
最妥善的办法是在本地添加到一个集合里面,之后实现一个添加到数据库的AddRange方法,只需要访问一次数据库即可。

问题应该出现

LogDataAccess.AddOrderRecord

这个方法里

用互斥量做个许可区,同时只能有一个线程访问。
或者直接用自带的lock关键字.
以及其他的一些线程同步的办法都可以。
数据库是绝对不能够多线程写入的,否则还会造成思索。必须进行线程同步或者使用队列

调试程序,同时数据库也打开调试功能来查看程序发来的SQL,对比内容,找到原因。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
你知道吗?

宣传栏