请教多线程操作同一个数据表时,怎么避免表死锁

问题描述

最近有一个数据采集的项目,要求可以多路并发,遇到多线程操作同一个数据表的问题,经常发生表死锁,求各位大侠帮忙,大约有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.
解决方案:
我也遇见这样的,同问!

时间: 2024-09-08 00:11:32

请教多线程操作同一个数据表时,怎么避免表死锁的相关文章

java多线程操作同一个变量的问题,难道是多核cpu所致?

问题描述 java多线程操作同一个变量的问题,难道是多核cpu所致? 大家请看代码和输出结果,我百思不得其解,为什么 amount只加了一次,开始我以为是static所致,就算去掉也还是有几率出现这样的结果,难道是多核cpu真的把两个线程同时执行了? package study; public class MyRunnable implements Runnable { public static int amount=0; @Override public void run() { // TO

WebGIS项目中利用mysql控制点库进行千万条数据坐标转换时的分表分区优化方案

文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1. 背景 项目中有1000万条历史案卷,为某地方坐标系数据,我们的真实需求是将地方坐标系坐标反转成WGS84坐标,如果现在需要将其转换成百度坐标系数据.常规方案是先建立好整个该市的本地坐标和百度坐标之间的控制点库后再进行转换.但是在具体实施中发现转换特别慢,由于控制点库也有200多万条记录,大概一个点需要一秒钟才能转换完. 2.将Update变成Insert关键字段值

关于java多线程操作invokeAll空指针的问题

问题描述 关于java多线程操作invokeAll空指针的问题 求救各位大神: public static void threadTestAll(String dirName) { long start = System.currentTimeMillis(); ExecutorService pool = Executors.newFixedThreadPool(30); List<Callable<String>> tasks = new ArrayList<Callab

windows注册表怎么打开?注册表在哪里进入?

一,windows xp/windows200X进入注册表 1.在开始菜单->运行 中输入 regedit即可进入注册表 二, windows7系统注册表 方法一:"开始"--"所有程序"--"附件"--"命令提示符"(此功能与运行的功能基本相同) 方法二:右键点击"开始菜单"--"属性"--"开始菜单"标签--"自定义"--拖动滑块到最后找

菜刀问一下,dataset的问题?如果N(N>1)同时操作同一个表的同一行 有人删除 有人修改 那个一个行数据是存在呢,还是被删除了!!!

问题描述 菜刀问一下,dataset的问题?如果N(N>1)同时操作同一个表的同一行有人删除 有人修改那个一个行数据是存在呢,还是被删除了!!! 解决方案 解决方案二:可以根据rowstate判断是否编辑.

Oracle当数据记录超过千万(50000000)条时,并且不在同一个库,如何从一个表导到另一个表?提高性能

问题描述 Oracle中,当数据记录超过千万(50000000)条时,并且不在同一个库,如何从一个表导到另一个表?提高性能DA库有表TA,有8千万条数据,DB库有同样结构的TB表,如何在将TA表导入TB表,并且如何优化性能?我是用数据链,导的过程中,没有经过任何字段的计算insertintotbselect*fromta@数据链可是这样出现临时表空间TEMP一直增大,导致硬盘没空间了,怎么办?并且TEMP不自动释放如果是在存储过程中加一个计数器,用游标每10000条COMMIT一次,这样会不会提

oracle11g-使用的ASP.NET,操作ORACLE数据时,在VS中执行的效果和PL中不一样

问题描述 使用的ASP.NET,操作ORACLE数据时,在VS中执行的效果和PL中不一样 简单说来就是我有一个表A,我向其中插入数据,用最简单的方式insert into A values(aa='aa',bb='bb'),在VS中会报出"关于ora-00942: 表或视图不存在"这个错误,将这个SQL语句原封不动的copy到PL里面,就能实现.还有就是我select * from A,在VS中执行得不到任何数据,但是在PL中能得到4行数据,与真实情况吻合,求解是什么情况... 解决方

emit-dapper.net IDataReader数据类型转换报错:操作可能会破坏运行时稳定性

问题描述 dapper.net IDataReader数据类型转换报错:操作可能会破坏运行时稳定性 object item3 = ((IDataRecord)this)[num8]; if (item3 is DBNull) { } else { string str1 = item3 as string; str = str1; if (str1 == null) { pluginType = (PluginType)Convert.ToByte(item3); } else { plugin

WPS2009打开数据透视表时实现自动刷新

当WPS2009文档中某一数据透视表的源数据发生变动后,需要对数据透视表进行手动刷新操作,以将变动后的数据更新到数据透视表中.其实我们可以通过设置,在打开WPS2009文档数据透视表时实现自动刷新数据.方法如下. 选中WPS数据透视表中任一单元格,激活"数据透视表"工具栏,然后单击"数据透视表(P)" 按钮旁边的倒三角形图标,在弹出的列表中选择"表格选项"命令,在"数据透视表选项"对话框中勾选"打开时刷新"