我正在制作一个程序,将 db1 中的所有表数据合并到 db2 中的一个表中。但它给出了死锁错误。
这是我的代码。
Parallel.ForEach(tableList, table =>
{
using (MySqlConnection conn = new MySqlConnection(DBconnection))
{
using (MySqlCommand cmd = new MySqlCommand(query, conn))
{
try
{
conn.Open();
cmd.CommandText = "INSERT INTO db2.targetTable (id, value1, value2) " +
"SELECT (SELECT id FROM db2.User u WHERE u.id = user LIMIT 1), " +
"value1, value2 FROM db1." + table;
cmd.CommandTimeout = 600000;
cmd.ExecuteNonQuery();
}
catch (Exception ex)
Console.WriteLine("ERROR : " + ex.Message);
}
}
}
我认为子查询导致了问题。
也许如果我添加这段代码,它可以解决问题:
Object sync = new Object();
lock (sync)
{
cmd.ExecuteNonQuery();
}
但我认为这效率不高。这是一个正确的解决方案吗?或者有更好的解决方案,请给我一个示例代码。
最佳答案
目前尚不清楚是什么导致了僵局。 (请注意,涉及 MyISAM 表的 SQL 操作会尝试获取整个表的独占锁,因此我假设您使用的是 InnoDB 或 MyISAM 之外的其他存储引擎。)
我会避免 SELECT 列表中的相关子查询,而是使用 JOIN 模式。我相信,通过 SELECT 列表中的子查询,MySQL 将为外部查询中返回的每一行执行该子查询。
INSERT INTO db2.targetTable (id, value1, value2)
SELECT u.id
, t.value1
, t.value2
FROM db1.table t
LEFT
JOIN db2.User u
ON u.id = t.user
语句中的子查询包含 LIMIT 1
条款。如果需要的话,因为 id
db2.User
中的列表不是唯一的(这会很奇怪,但可能),那么我上面给出的查询需要包含 GROUP BY <db1.table1 PRIMARY KEY>
,以避免从源行创建重复行。
如果 db1.table 的主键为 id
,那么:
INSERT INTO db2.targetTable (id, value1, value2)
SELECT u.id
, t.value1
, t.value2
FROM db1.table t
LEFT
JOIN db2.User u
ON u.id = t.user
GROUP BY t.id
关于c# - 使用并行复制表会导致 MySQL 死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21345184/