问题描述
最近有一个数据采集的项目,要求可以多路并发,遇到多线程操作同一个数据表的问题,经常发生表死锁,求各位大侠帮忙,大约有20-40个进程实例化读取类,类中Receive方法接收数据并存储上代码publicclassclsTranslateObj{privatevoidReceive(){intlenReceive=0;byte[]receivedByte=newbyte[BUFFER_SIZE];//接收返回字节数组_rtnStr=string.Empty;while(_flgConnect){_rtnStr=string.Empty;try{lenReceive=_translateClient.Receive(receivedByte,0,BUFFER_SIZE,SocketFlags.None);for(inti=0;i<lenReceive;i++){if(Convert.ToString(receivedByte[i],16).Length==1)_rtnStr+=("0"+Convert.ToString(receivedByte[i],16).ToString());elseif(Convert.ToString(receivedByte[i],16).Length==2)_rtnStr+=Convert.ToString(receivedByte[i],16).ToString();}//接收成功处理Console.WriteLine(_switchcode+"receive:"+lenReceive.ToString());for(intj=0;j<_rtnStr.Length;j+2){sqlCmd="insertintotagvalue(tagdatetime,tagcode,tagval)values(?tagdatetime,?tagcode,?tagval)";//tagdatetime=DateTime.Now;//tagcode=实验室号;//tagval=_rtnStr.Substring(j,2);}}catch(Exceptionex){Console.WriteLine(_switchcode+"Receive()error:"+ex.Message);}}}}
mysql中倒是有解决办法sqlCmd="insertDELAYEDintotagvalue(tagdatetime,tagcode,tagval)values(?tagdatetime,?tagcode,?tagval)";
DELAYED使用延迟插入操作DELAYED调节符应用于INSERT和REPLACE语句。当DELAYED插入操作到达的时候,服务器把数据行放入一个队列中,并立即给客户端返回一个状态信息,这样客户端就可以在数据表被真正地插入记录之前继续进行操作了。如果读取者从该数据表中读取数据,队列中的数据就会被保持着,直到没有读取者为止。接着服务器开始插入延迟数据行(delayed-row)队列中的数据行。在插入操作的同时,服务器还要检查是否有新的读取请求到达和等待。如果有,延迟数据行队列就被挂起,允许读取者继续操作。当没有读取者的时候,服务器再次开始插入延迟的数据行。这个过程一直进行,直到队列空了为止。
请问各位大侠,像其他Oracle、MSSQL等数据库怎么处理啊,急求啊,望各位赐教
解决方案
解决方案二:
死锁是什么概念?表现出哪些问题?真心求教!
解决方案三:
引用1楼的回复:
死锁是什么概念?表现出哪些问题?真心求教!
一个线程lock(A){sleep(1000);lock(B){..........}}一个线程lock(B){sleep(500);lock(A){..........}}两个线程启动最终死锁谁也无法继续运行具体去看书吧有个四条件
解决方案四:
为什么不是一个线程操作数据库部分,而是多个线程一起操作...就算不死锁,数据也有有问题吧
解决方案五:
该回复于2012-04-28 09:59:56被版主删除
解决方案六:
该回复于2012-04-28 10:06:32被版主删除
解决方案七:
没有人遇到过么
解决方案八:
这样的设计不太合理通常来说,是多个线程将数据插入一个队列,然后有个专门的线程来根据队列中的数据对数据库操作,这样就不会有问题
解决方案九:
引用7楼的回复:
这样的设计不太合理通常来说,是多个线程将数据插入一个队列,然后有个专门的线程来根据队列中的数据对数据库操作,这样就不会有问题
那请问队列的访问控制呢,多线程插入,还有存储线程读取、删除
解决方案十:
由一个线程读写表,其它线程则是处理数据
解决方案十一:
你可以用多线程把采集到的数据存储到一个队列里(存入队列的时候要锁住),然后再启动一个线程定时从队列把数据存入数据库,这样就不会有并发问题
解决方案十二:
引用2楼的回复:
引用1楼的回复:死锁是什么概念?表现出哪些问题?真心求教!一个线程lock(A){sleep(1000);lock(B){..........}}一个线程lock(B){sleep(500);lock(A){..........}}两个线程启动最终死锁谁也无法继续运行……
非常感谢!
解决方案十三:
能否说的再具体点啊
解决方案十四:
不应该啊,单纯的多线程insert不可能造成表锁的。你关键部分的入库操作的代码没有啊,严重怀疑是反复开关数据库连接造成的数据连接池响应不能,导致失败。
解决方案十五:
怎么没看到你线程在那里呀,是不是你用主线程,主线程死锁了。
解决方案:
引用13楼的回复:
不应该啊,单纯的多线程insert不可能造成表锁的。你关键部分的入库操作的代码没有啊,严重怀疑是反复开关数据库连接造成的数据连接池响应不能,导致失败。
publicstaticintSaveOnceData(DateTimetagdt,stringtagcd,stringtagvl){try{if(mc.State!=System.Data.ConnectionState.Open)mc.Open();intrtn=0;stringsqlCmd="insertDELAYEDintotagonce(tagdatetime,tagcode,tagval)values(?tagdatetime,?tagcode,?tagval)";if(mc!=null){MySqlCommandcmd=newMySqlCommand(sqlCmd,mc);cmd.CommandTimeout=5;cmd.Parameters.Add("?tagdatetime",MySqlDbType.Timestamp);cmd.Parameters["?tagdatetime"].Value=tagdt;cmd.Parameters.Add("?tagcode",MySqlDbType.Text);cmd.Parameters["?tagcode"].Value=tagcd;cmd.Parameters.Add("?tagval",MySqlDbType.Text);cmd.Parameters["?tagval"].Value=tagvl;rtn=cmd.ExecuteNonQuery();}returnrtn;}catch(Exceptione){return0;}}
解决方案:
用lock
解决方案:
引用16楼的回复:
用lock
能详细一点么
解决方案:
学习了,正好解决我的一个问题
解决方案:
可用个池,每个线程更新池中的数据,最后更新数据库。
解决方案:
综上所述,用lock控制多线程操作队列,然后单独开一个线程写数据库操作
解决方案:
为什么要一个数据库用多个线程来操作呢?
解决方案:
很明显,发数过大了,导致数据库连接数量不足,要解决问题,1,加大MySql的并发连接数量。2,限制你代码里面的并发连接数量。
解决方案:
但是为了采集并发,必须同步写数据库啊
解决方案:
以前我做数据采集的时候,也是用多线程一起插入,发现很容易出现死锁;然后我就用队列,多线程采集的时候只管向队列里写数据,然后另外开一条线程专门用来从队列取数据向数据库插入数据
解决方案:
10楼和24楼已经把解决方案说了将所有线程的插入数据库操作全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列),再就是楼上所说再开一个线程专门用来处理数据,但是注意要用委托,因为你开的这个插入数据的线程是独立的,而数据表属于UI线程的,我们是在这个线程里面用INVOKE方法将操作同步到UI线程里面。还有就是我感觉你的这个数据表是UI线程的,就要使用委托和INVOKE方法。如果只是单独的插入数据库,就没必要这样了,你可以将每个线程看做一个类,每个类都包含一个插入数据操作,也是插入同一张表格(数据库表格,不是UI里面的显示表格控件),这种情况是不会死锁的,至少200台设备同时插入数据我试过,没问题。
解决方案:
楼上的都没有看清楚,楼主说的是很多个进程,不是线程喔,进程之间的访问的话,如果数据库本身不支持多线程操作的话,那么就只好应用程序之间通信约定了,这是很复杂的。
解决方案:
引用25楼的回复:
10楼和24楼已经把解决方案说了将所有线程的插入数据库操作全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列),再就是楼上所说再开一个线程专门用来处理数据,但是注意要用委托,因为你开的这个插入数据的线程是独立的,而数据表属于UI线程的,我们是在这个线程里面用INVOKE方法将操作同步到UI线程里面。还有就是我感觉你的这个数据表是UI线程的……
我说的是线程,请教大侠为何我插入时明显丢失数据,我只开20个线程(因为有20个连接终端),但是不同的是我的终端插入有如下循环for(intj=0;j<_rtnStr.Length;j+2){sqlCmd="insertintotagvalue(tagdatetime,tagcode,tagval)values(?tagdatetime,?tagcode,?tagval)";//tagdatetime=DateTime.Now;//tagcode=实验室号;//tagval=_rtnStr.Substring(j,2);}
是不是因为循环插入造成独占表,使得其他线程插入数据丢失
解决方案:
引用25楼的回复:
10楼和24楼已经把解决方案说了将所有线程的插入数据库操作全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列),再就是楼上所说再开一个线程专门用来处理数据,但是注意要用委托,因为你开的这个插入数据的线程是独立的,而数据表属于UI线程的,我们是在这个线程里面用INVOKE方法将操作同步到UI线程里面。还有就是我感觉你的这个数据表是UI线程的……
我说的是线程,但是如大侠所说我开20线程同时插入表确实造成数据丢失了(有20个设备),为啥啊,是不是我在线程中循环插入数据造成线程独占表?使其他线程无法插入,数据丢失?for(intj=0;j<_rtnStr.Length;j+2){sqlCmd="insertintotagvalue(tagdatetime,tagcode,tagval)values(?tagdatetime,?tagcode,?tagval)";//tagdatetime=DateTime.Now;//tagcode=实验室号;//tagval=_rtnStr.Substring(j,2);}
解决方案:
批量加添20个设备每产生一条数据则添加List<T>中如objectlocObj=newobject();List<T>data=newList<T>();获取数据方法中lock(locObj){data.Add(数据);if(data.Count>=20){//调用保存数据方法InsertData(data);data.Cler();}}//使用批量添加数据SqlBulkCopy类voidInsertData(List<T>list){}
解决方案:
应该不是数据库的问题,毕竟一个数据库卖那么贵你在插入数据库操作那里加个输出函数调试试一下,看下每个设备是不是都执行了插入操作,然后再来讨论下。
解决方案:
加个输出调试在插入数据库的地方,看看是不是每个设备都执行了插入数据库操作,然后就是你说死锁,应该会抛出异常,把异常贴出来看看。应该不会是数据库的问题,想想一个数据库多贵啊
解决方案:
引用28楼的回复:
引用25楼的回复:10楼和24楼已经把解决方案说了将所有线程的插入数据库操作全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列),再就是楼上所说再开一个线程专门用来处理数据,但是注意要用委托,因为你开的这个插入数据的线程是独立的,而数据表属于UI线程的,我们是在这个线程里面用INVOKE方法将操作同步到UI线程里面。还有就是我感觉……
既然你插入的数据列一样,为什么不先存进入一个table中然后用SqlBulkCopy入库呢
解决方案:
引用32楼的回复:
引用28楼的回复:引用25楼的回复:10楼和24楼已经把解决方案说了将所有线程的插入数据库操作全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列),再就是楼上所说再开一个线程专门用来处理数据,但是注意要用委托,因为你开的这个插入数据的线程是独立的,而数据表属于UI线程的,我们是在这个线程里面用INVOKE方法将操作同步到UI……
SqlBulkCopy入库是什么技术啊
解决方案:
批量导入
解决方案:
用不了那么复杂吧?在类里面声明一个全局对象privatestaticreadonlyobjectlocker=newobject();............然后在你的代码lock(locker){rtn=cmd.ExecuteNonQuery();}
解决方案:
设计一下代码逻辑,尽量不要使用嵌套锁
解决方案:
不要把与数据库有关的操作放在通讯线程中单开一个线程统一操作数据库
解决方案:
貌似跟死不死锁关系不大是设计上的问题
解决方案:
高手....
解决方案:
该回复于2012-05-08 22:25:11被版主删除
解决方案:
遇到相同问题,求解
解决方案:
频繁操作数据库,使用长链接。不停建立链接,压力大。数据库操作建立队列排队等待。
解决方案:
10楼和24楼已经把解决方案说了将所有线程的插入数据库操作全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列),再就是楼上所说再开一个线程专门用来处理数据,但是注意要用委托,因为你开的这个插入数据的线程是独立的,而数据表属于UI线程的,我们是在这个线程里面用INVOKE方法将操作同步到UI线程里面。还有就是我感觉你的这个数据表是UI线程的,就要使用委托和INVOKE方法。如果只是单独的插入数据库,就没必要这样了,你可以将每个线程看做一个类,每个类都包含一个插入数据操作,也是插入同一张表格(数据库表格,不是UI里面的显示表格控件),这种情况是不会死锁的,至少200台设备同时插入数据我试过,没问题。
解决方案:
死锁就是两个或多个线程抢一个对象,最后导致多线程卡住,用lock防止
解决方案:
数据库连接的死锁最好的解决办法,就是不同线程用不同的数据库连接对象去执行sql.
解决方案:
我也遇见这样的,同问!