采用多线程对数据库读写引发冲突

蜜莉恩 2013-08-08 01:51:20
数据库里存了几百台系统信息,要定时从数据库查询系统列表,连接到每台系统,采集一些数据,然后把采集到的数据再存到数据库中,便于日后查询。
因为系统数量庞大,所以采用的是多线程操作,这样可以提高采集数据的速度。但问题就在于收集到数据以后插入数据库时发生冲突,因为常常多个进程都想要把自己的数据插入,而且是插入同一个表,但只有一个进程能真正取得写入权(个人猜测是因为insert的时候数据库自动把表给lock了?),因此导致其他进程的数据没法写入而丢失。
有没有办法解决这一问题?
...全文
952 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
蜜莉恩 2013-08-09
  • 打赏
  • 举报
回复
忘了提,我查看了下error log,当时报的错是: server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request.
蜜莉恩 2013-08-09
  • 打赏
  • 举报
回复
终于解决了!问题不是之前猜测的conflicts,而是数据库的connection出了问题。 解决办法是在每个fork的子进程中重新创建一个数据库连接。 function parentFunction() { get some tasks $pid = pcntl_fork(); // using fork() to create sub-processes if (!$pid) { // now inside each child $conn = sql_conn(...) get data insert data into database // all the children are supposed to operate on the same table exit(); } } 虽然我还是想不明白,每个子进程在写入的时候应该创建的是自己的连接,按说相互之间不影响的。 但从问题看来他们共享的是parent的连接,一旦子进程写入完成,并close了connection,其他的进程如果正要写入的话就会被影响。 有没有人能解释为什么这么做就能解决问题?
Shawn 2013-08-08
  • 打赏
  • 举报
回复
引用 5 楼 AAA428 的回复:
[quote=引用 1 楼 wwwwgou 的回复:] #1.保证一个线程只取到一台服务器的信息,并进行收集 #2.收集完成后,有一个“并发”插入的过程。数据库默认隔离级别下,INSERT不会相互阻塞。除非你提高的隔离级别或建立了“唯一索引”。 #3.其实你不用猜,用SQL SERVER的活动和监视器,看一下阻塞的原因是什么,就明白了。再想办法解决。 #4.楼主指的“其他进程的数据没法写入而丢失”什么意思?数据会丢失吗?
另外,看到网上有人说“由于插入动作要检查关键字是否重复,不可以并行操作的”,觉得有点道理,但和您说的第二条又有点儿矛盾[/quote] 这个关键字段重复,就是指关键字段唯一的意思,跟我说的除非建立了“唯一索引”是一样道理的。
Q315054403 2013-08-08
  • 打赏
  • 举报
回复
一千台同时往表里插入数据也没问题呀。。你所说的LOCK,一定是设计上问题,比如指定表锁或KEY锁未释放
蜜莉恩 2013-08-08
  • 打赏
  • 举报
回复
引用 3 楼 hdhai9451 的回复:
对数据插入你有没有使用事务,使用事务再多的进程排队等待,也不会因此而错误
sorry,我在数据库方面还是新手。。很新,事务是什么?要怎么应用?能具体点儿吗
蜜莉恩 2013-08-08
  • 打赏
  • 举报
回复
引用 1 楼 wwwwgou 的回复:
#1.保证一个线程只取到一台服务器的信息,并进行收集 #2.收集完成后,有一个“并发”插入的过程。数据库默认隔离级别下,INSERT不会相互阻塞。除非你提高的隔离级别或建立了“唯一索引”。 #3.其实你不用猜,用SQL SERVER的活动和监视器,看一下阻塞的原因是什么,就明白了。再想办法解决。 #4.楼主指的“其他进程的数据没法写入而丢失”什么意思?数据会丢失吗?
另外,看到网上有人说“由于插入动作要检查关键字是否重复,不可以并行操作的”,觉得有点道理,但和您说的第二条又有点儿矛盾
Shawn 2013-08-08
  • 打赏
  • 举报
回复
我一般会选择相信SQL SERVE,它说database is unavailable,那可能就是原因。 如果INSERT时遇见网络或其它原因导致失败,建议在程序中加异常捕获并重试功能,重试3次仍失败的,先记录在本地数据库。 楼主加油,继续查原因啊。
Andy__Huang 2013-08-08
  • 打赏
  • 举报
回复
对数据插入你有没有使用事务,使用事务再多的进程排队等待,也不会因此而错误
蜜莉恩 2013-08-08
  • 打赏
  • 举报
回复
哈哈,回复下: 1 一个线程只负责一台服务器 2 参见我对4的回答 3 确实应该查看下error log,依稀记得只报错说database is unavailable 4 比如说,我有200台机器,那200个线程取得信息后,应该插入200条记录对吧,但事实是数据库里只有120条记录。 然后我在程序的每一步测试了一下, for each $sys in $sys_list { 1. ssh to $sys to get data echo "1" 2. $sql = "insert data into DB" echo "2" 3. sql_command($sql) } 一直到第二步都没问题,所以我认为问题出在第三步,也就是insert的时候出现了问题。
Shawn 2013-08-08
  • 打赏
  • 举报
回复
#1.保证一个线程只取到一台服务器的信息,并进行收集 #2.收集完成后,有一个“并发”插入的过程。数据库默认隔离级别下,INSERT不会相互阻塞。除非你提高的隔离级别或建立了“唯一索引”。 #3.其实你不用猜,用SQL SERVER的活动和监视器,看一下阻塞的原因是什么,就明白了。再想办法解决。 #4.楼主指的“其他进程的数据没法写入而丢失”什么意思?数据会丢失吗?

34,590

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧