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

tshtscc 2012-04-28 09:24:10
最近有一个数据采集的项目,要求可以多路并发,遇到多线程操作同一个数据表的问题,经常发生表死锁,求各位大侠帮忙,大约有20-40个进程实例化读取类,类中Receive方法接收数据并存储
上代码

public class clsTranslateObj
{
private void Receive()
{
int lenReceive = 0;
byte[] receivedByte = new byte[BUFFER_SIZE]; //接收返回字节数组

_rtnStr = string.Empty;

while (_flgConnect)
{
_rtnStr = string.Empty;

try
{
lenReceive = _translateClient.Receive(receivedByte, 0, BUFFER_SIZE, SocketFlags.None);

for (int i = 0; i < lenReceive; i++)
{
if (Convert.ToString(receivedByte[i], 16).Length == 1)
_rtnStr += ("0" + Convert.ToString(receivedByte[i], 16).ToString());
else if (Convert.ToString(receivedByte[i], 16).Length == 2)
_rtnStr += Convert.ToString(receivedByte[i], 16).ToString();
}

//接收成功处理
Console.WriteLine(_switchcode + " receive:" + lenReceive.ToString());

for(int j = 0; j < _rtnStr.Length; j+2)
{
sqlCmd = "insert into tagvalue(tagdatetime, tagcode, tagval) values(?tagdatetime, ?tagcode, ?tagval)";

//tagdatetime = DateTime.Now;
//tagcode = 实验室号;
//tagval = _rtnStr.Substring(j, 2);
}

}
catch(Exception ex)
{
Console.WriteLine(_switchcode + " Receive() error:" + ex.Message);
}
}
}
}


mysql中倒是有解决办法

sqlCmd = "insert DELAYED into tagvalue(tagdatetime, tagcode, tagval) values(?tagdatetime, ?tagcode, ?tagval)";


DELAYED 使用延迟插入操作DELAYED调节符应用于INSERT和REPLACE语句。当DELAYED插入操作到达的时候,服务器把数据行放入一个队列中,并立即给客户端返回一个状态信息,这样客户端就可以在数据表被真正地插入记录之前继续进行操作了。如果读取者从该数据表中读取数据,队列中的数据就会被保持着,直到没有读取者为止。接着服务器开始插入延迟数据行(delayed-row)队列中的数据行。在插入操作的同时,服务器还要检查是否有新的读取请求到达和等待。如果有,延迟数据行队列就被挂起,允许读取者继续操作。当没有读取者的时候,服务器再次开始插入延迟的数据行。 这个过程一直进行,直到队列空了为止。


请问各位大侠,像其他Oracle、MSSQL等数据库怎么处理啊,急求啊,望各位赐教
...全文
5650 46 打赏 收藏 转发到动态 举报
写回复
用AI写文章
46 条回复
切换为时间正序
请发表友善的回复…
发表回复
woyoumeng 2014-08-26
  • 打赏
  • 举报
回复
我也遇见这样的,同问!
cchvsgame 2013-01-15
  • 打赏
  • 举报
回复 1
数据库连接的死锁最好的解决办法,就是不同线程用不同的数据库连接对象去执行sql.
a123465123465 2013-01-14
  • 打赏
  • 举报
回复
死锁就是两个或多个线程抢一个对象,最后导致多线程卡住,用lock防止
luobing261314 2013-01-14
  • 打赏
  • 举报
回复
10楼和24楼 已经把解决方案说了 将所有 线程的 插入数据库操作 全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列), 再就是楼上所说 再开一个线程专门用来处理数据, 但是注意要用委托,因为你开的这个插入数据的线程 是独立的,而数据表属于UI线程的, 我们是在这个线程里面用INVOKE方法 将操作同步到 UI线程里面。 还有就是我感觉 你的这个数据表是UI线程的,就要使用委托和INVOKE方法。 如果只是单独的 插入数据库,就没必要这样了,你可以将每个线程 看做一个类,每个类都包含一个插入数据操作,也是插入同一张表格(数据库表格,不是UI里面的显示表格控件), 这种情况 是不会死锁的,至少200台设备同时插入数据 我试过,没问题。
amlove 2013-01-14
  • 打赏
  • 举报
回复
频繁操作数据库,使用长链接。 不停建立链接,压力大。 数据库操作建立队列排队等待。
howareyou20122 2013-01-10
  • 打赏
  • 举报
回复
遇到相同问题,求解
叫我三三 2012-05-08
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 的回复:]

引用 25 楼 的回复:
10楼和24楼 已经把解决方案说了
将所有 线程的 插入数据库操作 全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列), 再就是楼上所说 再开一个线程专门用来处理数据, 但是注意要用委托,因为你开的这个插入数据的线程 是独立的,而数据表属于UI线程的, 我们是在这个线程里面用INVOKE方法 将操作同步到 UI线程里面。
还有就是我感觉……
[/Quote]
既然你插入的数据列一样,为什么不先存进入一个table中
然后用SqlBulkCopy入库呢
aishuju1 2012-05-08
  • 打赏
  • 举报
回复
高手....
请叫我卷福 2012-05-08
  • 打赏
  • 举报
回复
貌似跟死不死锁关系不大 是设计上的问题
请叫我卷福 2012-05-08
  • 打赏
  • 举报
回复
不要把与数据库有关的操作 放在 通讯线程中 单开一个线程统一操作数据库
  • 打赏
  • 举报
回复
设计一下代码逻辑,尽量不要使用嵌套锁
花痴 2012-05-08
  • 打赏
  • 举报
回复
用不了那么复杂吧?
在类里面声明一个全局对象

private static readonly object locker = new object();
......
......
然后在你的代码
lock(locker)
{
rtn = cmd.ExecuteNonQuery();
}
NewUser2008 2012-05-08
  • 打赏
  • 举报
回复
批量导入
tshtscc 2012-05-08
  • 打赏
  • 举报
回复
[Quote=引用 32 楼 的回复:]
引用 28 楼 的回复:

引用 25 楼 的回复:
10楼和24楼 已经把解决方案说了
将所有 线程的 插入数据库操作 全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列), 再就是楼上所说 再开一个线程专门用来处理数据, 但是注意要用委托,因为你开的这个插入数据的线程 是独立的,而数据表属于UI线程的, 我们是在这个线程里面用INVOKE方法 将操作同步到 UI……
[/Quote]
SqlBulkCopy入库是什么技术啊
_贺兰 2012-05-04
  • 打赏
  • 举报
回复
加个 输出调试 在 插入数据库的 地方,看看 是不是每个 设备都 执行了 插入数据库操作,然后就是你说死锁,应该会抛出异常,把异常贴出来看看。
应该不会是数据库的问题,想想一个数据库多贵啊
_贺兰 2012-05-04
  • 打赏
  • 举报
回复
应该不是数据库的问题,毕竟一个数据库卖那么贵
你在插入数据库操作 那里加个 输出函数调试 试一下,看下每个设备是不是 都执行了 插入操作,然后再来讨论下。

NewUser2008 2012-05-04
  • 打赏
  • 举报
回复
批量加添 20个设备每产生一条数据 则 添加List<T> 中



object locObj = new object();


List<T> data = new List<T>();


获取数据方法中

lock(locObj)
{
data.Add(数据);


if(data.Count>= 20)
{
//调用保存数据方法

InsertData(data);

data.Cler();
}

}


//使用批量添加数据 SqlBulkCopy 类
void InsertData(List<T> list)
{

}





tshtscc 2012-05-04
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 的回复:]
10楼和24楼 已经把解决方案说了
将所有 线程的 插入数据库操作 全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列), 再就是楼上所说 再开一个线程专门用来处理数据, 但是注意要用委托,因为你开的这个插入数据的线程 是独立的,而数据表属于UI线程的, 我们是在这个线程里面用INVOKE方法 将操作同步到 UI线程里面。
还有就是我感觉 你的这个数据表是UI线程的……
[/Quote]
我说的是线程,但是如大侠所说我开20线程同时插入表确实造成数据丢失了(有20个设备),为啥啊,是不是我在线程中循环插入数据造成线程独占表?使其他线程无法插入,数据丢失?
for(int j = 0; j < _rtnStr.Length; j+2)
{
sqlCmd = "insert into tagvalue(tagdatetime, tagcode, tagval) values(?tagdatetime, ?tagcode, ?tagval)";

//tagdatetime = DateTime.Now;
//tagcode = 实验室号;
//tagval = _rtnStr.Substring(j, 2);
}

tshtscc 2012-05-04
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 的回复:]
10楼和24楼 已经把解决方案说了
将所有 线程的 插入数据库操作 全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列), 再就是楼上所说 再开一个线程专门用来处理数据, 但是注意要用委托,因为你开的这个插入数据的线程 是独立的,而数据表属于UI线程的, 我们是在这个线程里面用INVOKE方法 将操作同步到 UI线程里面。
还有就是我感觉 你的这个数据表是UI线程的……
[/Quote]
我说的是线程,请教大侠为何我插入时明显丢失数据,我只开20个线程(因为有20个连接终端),但是不同的是我的终端插入有如下循环
for(int j = 0; j < _rtnStr.Length; j+2)
{
sqlCmd = "insert into tagvalue(tagdatetime, tagcode, tagval) values(?tagdatetime, ?tagcode, ?tagval)";

//tagdatetime = DateTime.Now;
//tagcode = 实验室号;
//tagval = _rtnStr.Substring(j, 2);
}


是不是因为循环插入造成独占表,使得其他线程插入数据丢失
tshtscc 2012-05-03
  • 打赏
  • 举报
回复
但是为了采集并发,必须同步写数据库啊
加载更多回复(23)

111,126

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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