请教多线程操作同一个数据表时,怎么避免表死锁 一个线程lock(A){sleep(1000);lock(B){..........}}一个线程lock(B){sleep(500);lock(A){..........}}两个线程启动最终死锁谁也无法继续运行具体去看书吧有个四条件 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 不应该啊,单纯的多线程insert不可能造成表锁的。你关键部分的入库操作的代码没有啊,严重怀疑是反复开关数据库连接造成的数据连接池响应不能,导致失败。 public static int SaveOnceData(DateTime tagdt, string tagcd, string tagvl) { try { if (mc.State != System.Data.ConnectionState.Open) mc.Open(); int rtn = 0; string sqlCmd = "insert DELAYED into tagonce(tagdatetime, tagcode, tagval) values(?tagdatetime, ?tagcode, ?tagval)"; if (mc != null) { MySqlCommand cmd = new MySqlCommand(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(); } return rtn; } catch (Exception e) { return 0; } } 综上所述,用lock 控制多线程操作 队列,然后单独开一个线程写数据库操作 很明显,发数过大了,导致数据库连接数量不足,要解决问题,1,加大MySql的并发连接数量。2,限制你代码里面的并发连接数量。 10楼和24楼 已经把解决方案说了将所有 线程的 插入数据库操作 全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列), 再就是楼上所说 再开一个线程专门用来处理数据, 但是注意要用委托,因为你开的这个插入数据的线程 是独立的,而数据表属于UI线程的, 我们是在这个线程里面用INVOKE方法 将操作同步到 UI线程里面。 还有就是我感觉 你的这个数据表是UI线程的,就要使用委托和INVOKE方法。 如果只是单独的 插入数据库,就没必要这样了,你可以将每个线程 看做一个类,每个类都包含一个插入数据操作,也是插入同一张表格(数据库表格,不是UI里面的显示表格控件), 这种情况 是不会死锁的,至少200台设备同时插入数据 我试过,没问题。 我说的是线程,请教大侠为何我插入时明显丢失数据,我只开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); }是不是因为循环插入造成独占表,使得其他线程插入数据丢失 我说的是线程,但是如大侠所说我开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); } 批量加添 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){ } 既然你插入的数据列一样,为什么不先存进入一个table中然后用SqlBulkCopy入库呢 用不了那么复杂吧?在类里面声明一个全局对象private static readonly object locker = new object();............然后在你的代码lock(locker) { rtn = cmd.ExecuteNonQuery();} 10楼和24楼 已经把解决方案说了将所有 线程的 插入数据库操作 全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列), 再就是楼上所说 再开一个线程专门用来处理数据, 但是注意要用委托,因为你开的这个插入数据的线程 是独立的,而数据表属于UI线程的, 我们是在这个线程里面用INVOKE方法 将操作同步到 UI线程里面。 还有就是我感觉 你的这个数据表是UI线程的,就要使用委托和INVOKE方法。 如果只是单独的 插入数据库,就没必要这样了,你可以将每个线程 看做一个类,每个类都包含一个插入数据操作,也是插入同一张表格(数据库表格,不是UI里面的显示表格控件), 这种情况 是不会死锁的,至少200台设备同时插入数据 我试过,没问题。 死锁就是两个或多个线程抢一个对象,最后导致多线程卡住,用lock防止 数据库连接的死锁最好的解决办法,就是不同线程用不同的数据库连接对象去执行sql. c#winform panel的问题 正则抓取网页table并把获取的数据存入数据库 为什么我获得listview中的值时会报错?? DataGird中的问题 关于virtual,new ,override 如何更改客户端IP来进行欺骗,欢迎补充。 Radiobuttonlist的问题 Delphi程序转成C#程序的问题,请达人指点! 请教一个类的名字 求帮忙解释下C#链表中头引用head的相关意思? 请教C#多个组合键的处理方法 窗口中的Timer问题
你关键部分的入库操作的代码没有啊,严重怀疑是反复开关数据库连接造成的数据连接池响应不能,导致失败。
public static int SaveOnceData(DateTime tagdt, string tagcd, string tagvl)
{
try
{
if (mc.State != System.Data.ConnectionState.Open)
mc.Open(); int rtn = 0; string sqlCmd = "insert DELAYED into tagonce(tagdatetime, tagcode, tagval) values(?tagdatetime, ?tagcode, ?tagval)"; if (mc != null)
{
MySqlCommand cmd = new MySqlCommand(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();
} return rtn;
}
catch (Exception e)
{
return 0;
}
}
1,加大MySql的并发连接数量。
2,限制你代码里面的并发连接数量。
将所有 线程的 插入数据库操作 全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列), 再就是楼上所说 再开一个线程专门用来处理数据, 但是注意要用委托,因为你开的这个插入数据的线程 是独立的,而数据表属于UI线程的, 我们是在这个线程里面用INVOKE方法 将操作同步到 UI线程里面。
还有就是我感觉 你的这个数据表是UI线程的,就要使用委托和INVOKE方法。
如果只是单独的 插入数据库,就没必要这样了,你可以将每个线程 看做一个类,每个类都包含一个插入数据操作,也是插入同一张表格(数据库表格,不是UI里面的显示表格控件), 这种情况 是不会死锁的,至少200台设备同时插入数据 我试过,没问题。
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);
}
是不是因为循环插入造成独占表,使得其他线程插入数据丢失
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);
}
List<T> data = new List<T>();
获取数据方法中lock(locObj)
{
data.Add(数据);
if(data.Count>= 20)
{
//调用保存数据方法 InsertData(data); data.Cler();
}}
//使用批量添加数据 SqlBulkCopy 类
void InsertData(List<T> list)
{
}
然后用SqlBulkCopy入库呢
在类里面声明一个全局对象private static readonly object locker = new object();
......
......
然后在你的代码
lock(locker)
{
rtn = cmd.ExecuteNonQuery();
}
将所有 线程的 插入数据库操作 全部委托到一个地方(我们是UI线程),然后插入队列,上锁(防止同时插入队列), 再就是楼上所说 再开一个线程专门用来处理数据, 但是注意要用委托,因为你开的这个插入数据的线程 是独立的,而数据表属于UI线程的, 我们是在这个线程里面用INVOKE方法 将操作同步到 UI线程里面。
还有就是我感觉 你的这个数据表是UI线程的,就要使用委托和INVOKE方法。
如果只是单独的 插入数据库,就没必要这样了,你可以将每个线程 看做一个类,每个类都包含一个插入数据操作,也是插入同一张表格(数据库表格,不是UI里面的显示表格控件), 这种情况 是不会死锁的,至少200台设备同时插入数据 我试过,没问题。