C#如何在长时间运行的查询中防止数据丢失?

时间:2017-08-02 07:44:12

标签: c# database winforms ms-access crash

我有以下代码需要大约一个小时来运行几十万行:

public void Recording(int rowindex)
    {
        using (OleDbCommand cmd = new OleDbCommand())
        {
            try
            {
                using (OleDbConnection connection = new OleDbConnection(Con))
                {
                    cmd.Connection = connection;
                    connection.Open();
                    using (OleDbTransaction Scope = connection.BeginTransaction(SD.IsolationLevel.ReadCommitted))
                    {
                        try
                        {
                            string Query = @"UPDATE [" + SetupAction.currentTable + "] set Description=@Description, Description_Department=@Description_Department, Accounts=@Accounts where ID=@ID";
                            cmd.Parameters.AddWithValue("@Description", VirtualTable.Rows[rowindex][4].ToString());
                            cmd.Parameters.AddWithValue("@Description_Department", VirtualTable.Rows[rowindex][18].ToString());
                            cmd.Parameters.AddWithValue("@Accounts", VirtualTable.Rows[rowindex][22].ToString());
                            cmd.Parameters.AddWithValue("@ID", VirtualTable.Rows[rowindex][0].ToString());
                            cmd.CommandText = Query;
                            cmd.Transaction = Scope;
                            cmd.ExecuteNonQuery();
                            Scope.Commit();
                        }
                        catch (OleDbException odex)
                        {
                            MessageBox.Show(odex.Message);
                            Scope.Rollback();
                        }
                    }
                }
            }
            catch (OleDbException ex)
            {
                MessageBox.Show("SQL: " + ex);
            }
        }
    }

它按预期工作,但是今天我的程序在运行查询时崩溃了(在for循环中,rowindex是数据表的索引),计算机崩溃,当我重新启动程序时,它说:< / p>

  

多步OleDB操作生成错误:后跟我的连接字符串。

发生的事情是数据库是完全不可交互的,即使是微软访问的恢复方法似乎也无法帮助到这里。

我读过这可能是因为数据库的数据结构与预期的数据结构有所不同。我的问题是,我如何防止这种情况,因为我无法确定我的程序是否突然停止运行。

我可能有办法以某种方式重组它,也许有一个我不知道的功能。可能是在发生崩溃时发送了一些空查询,但我不知道如何阻止它。

2 个答案:

答案 0 :(得分:2)

Jet / ACE数据库引擎已经尝试避免损坏并自动从灾难性事件中恢复(连接丢失,计算机崩溃)。通过完全提交(或丢弃)多个操作,事务可以进一步防止不一致的数据。但最终可能会出现一些巧合的系统故障,这可能会终止某个关键写入位置的操作,从而在数据库文件中产生严重的不一致。定期和及时备份是整体解决方案的一部分。对于非常长的操作,可能需要在操作之前制作整个数据库文件的自动副本。

否则,一个极端的选择是

  1. 创建第二个中间数据库,首先插入所有数据。 (只需要做一次。)
  2. 在此中间数据​​库中,将链接表创建到永久工作数据库中的相关表。
  3. 同样在中间数据库中,创建一个索引的本地表,该表镜像将要插入数据的链接表结构。或者如果中间数据库和表已经存在,请清除本地表(即删除所有行)。
  4. 将当前的软件插入本地中间表。
  5. 运行单个查询,然后从临时表更新链接表。在事务中包装更新。
    • 这里是链接表的好处,它可以在SQL查询中引用,就像任何本地表一样。您只需要显式打开中间数据。换句话说,只需执行UPDATE LocalTable INNER JOIN LinkedTable ON LocalTable.UpdateID = LinkedTable.ID SET LinkedTable.Data = LocalTable.Data
    • 等简单查询即可
  6. 此过程的好处是,从一个Access表中更新一个Access表的单个查询可能非常快,可能比代码中的多个更新操作快得多。这可以降低更新代码中的错误对数据库产生负面影响的可能性。这当然不能完全消除可能影响数据库的随机计算机崩溃,但减少执行多个连接和更新查询的时间可能会降低它的可能性。

答案 1 :(得分:1)

我认为你的catch块是错误的,因为如果你得到OleDbException以外的异常,你将不会回滚事务

public void OnApplicationPause(bool paused) {
if(paused) {
// Game is paused, start service to get notifications
} else {
// Game is unpaused, stop service notifications. 
}

异常,而不是 OleDbException 。例外情况可能来自任何地方,而不一定是Ole DB,你仍然希望回滚到目前为止你所做的一切。

话虽如此,如果你有几十万行,我会认真考虑批量更新,并且每次迭代只需处理几千个每次迭代的交易

就交易行为而言,主要问题是:您是否真的想要回滚到目前为止已经更新的一切以防发生故障,或者只是重试/继续您的位置离开?如果答案是您要重试/继续,那么您可能希望创建一个try { // ... Scope.Commit(); } catch (Exception ex) { MessageBox.Show(ex.Message); Scope.Rollback(); } 表或类似的...以及每次迭代所需的所有信息