【问题标题】:ODBC behaving asynchronously?ODBC 行为异步?
【发布时间】:2020-11-24 13:01:55
【问题描述】:

我发现当我使用 OdbcConnection 更新 Jet SQL 数据库时,c# 代码很快完成,但数据库在数百毫秒内没有更新。因此,当我在更新数据库的代码完成后立即读取数据库时,我正在读取旧数据。

在一个特定的 UPDATE 之后,我会立即重新加载一个网格,它会显示未更改的数据,除非我暂停。 SQL 命令相当简单,例如: UPDATE MyTable SET MyField = 3 WHERE ID = 3000

using (var connection = new OdbcConnection(connectionString))

{
    connection.Open();
    using (var command = new OdbcCommand(SQLText, connection))
    {
        command.Parameters = SQLParams;
        int dummy = command.ExecuteNonQuery();
        //System.Threading.Thread.Sleep(800);
    }
}

如果我取消注释 Sleep 行,之后会读取更新的数据,否则会读取旧数据。

我正在使用本地数据库运行,所以并不是其他用户让数据库忙。

即使应用程序在更新后终止并且另一个应用程序立即读取数据,另一个应用程序也在读取旧数据。这让我认为它是 ODBC 功能(而不是 OdbcConnection 本身)中固有的东西,它不会立即处理 SQL。

我可以立即处理 SQL 吗?

或者,我可以询问 ODBC 以查找处理完成的时间吗?

【问题讨论】:

  • 这可能是共享问题。您如何尝试读回数据? using 块正在处理命令和连接。在处理连接之前,文件被 Windows 锁定,因此您可以在只读模式下获得数据的副本。
  • @jdweng 感谢您的想法。在更新的 exe 关闭后,我正在通过不同的 OdbcConnection 或从不同的 exe 读取数据。在这两种情况下,我都发现了陈旧的数据。我尝试在 UPDATE 之后添加一个 Dispose 和新的 OdbcConnection(在同一个 exe 中读取的连接上),但问题仍然存在。当然,在更新的 exe 关闭后从不同的 exe 读取意味着更新 exe 中的所有内容在仍然读取陈旧数据之前已关闭和处置。
  • 如果您有主键,则需要检查虚拟值是否为零。更新时为零表示密钥不在数据库中,您必须进行插入。当您执行插入并且 dummy 为零时,密钥已在数据库中,您需要进行更新。
  • @jdweng UPDATE 的虚拟值为 1(报告为已更新的记录数)。而且记录确实最终会更新,只是在 ExecuteNonQuery 完成时还没有完成,它是 500ms - 800ms 之后
  • 我使用 JET 和 ODBC 已经很长时间了,但从未见过这种类型的结果。我看到的唯一问题是共享发生时。 JET 并不意味着共享(或并行处理)。您使用的是什么类型的数据库(扩展)?文件在哪里?如果文件有多大?如果你得到一个 1 的虚拟值,那么数据就被写入了。所以要么是其他东西改变了这个值,要么你不是从同一个位置读取。我还看到了数据库损坏且数据未正确保存的情况。使用 JET,数据库可能会严重碎片化或损坏。

标签: c# ms-access odbc


【解决方案1】:

只是为了确认this answer 确实也适用于 ODBC,这段代码……

using System;
using System.Data.Odbc;

namespace odbcConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var connectionString = 
                  @"DRIVER={Microsoft Access Driver (*.mdb)};"
                + @"DBQ=C:\Users\Public\mdbTest.mdb";
            using (var con1 = new OdbcConnection(connectionString))
            using (var con2 = new OdbcConnection(connectionString))
            {
                con1.Open();
                con2.Open();
                using (var cmd1 = new OdbcCommand())
                using (var cmd2 = new OdbcCommand())
                {
                    cmd1.Connection = con1;
                    cmd2.Connection = con2;

                    var tableName = "so64987075";
                    var selectCommand = $"SELECT MyField FROM {tableName} WHERE ID = 3000";
                    cmd1.CommandText = selectCommand;
                    int startValue = (int)cmd1.ExecuteScalar();
                    Console.WriteLine($"{DateTime.Now} - con1 - MyField = {startValue}");
                    cmd1.CommandText = $"UPDATE {tableName} SET MyField = MyField + 1 WHERE ID = 3000";
                    cmd1.ExecuteNonQuery();
                    Console.WriteLine($"{DateTime.Now} - con1 - UPDATE completed.");
                    //con1.Close();

                    cmd2.CommandText = selectCommand;
                    int newValue = -1;
                    do
                    {
                        newValue = (int)cmd2.ExecuteScalar();
                        Console.WriteLine($"{DateTime.Now} - con2 - MyField = {newValue}");
                        System.Threading.Thread.Sleep(1000);
                    } while (newValue == startValue);
                }
            }
        }
    }
}

... 产生以下控制台输出:

2020-11-27 12:05:24 - con1 - MyField = 8
2020-11-27 12:05:24 - con1 - UPDATE completed.
2020-11-27 12:05:24 - con2 - MyField = 8
2020-11-27 12:05:25 - con2 - MyField = 8
2020-11-27 12:05:26 - con2 - MyField = 8
2020-11-27 12:05:27 - con2 - MyField = 8
2020-11-27 12:05:28 - con2 - MyField = 8
2020-11-27 12:05:29 - con2 - MyField = 9

我可以立即处理 SQL 吗?

是的,通过关闭连接。取消注释上面的 //con1.Close(); 行会产生

2020-11-27 12:07:19 - con1 - MyField = 9
2020-11-27 12:07:19 - con1 - UPDATE completed.
2020-11-27 12:07:19 - con2 - MyField = 10

【讨论】:

  • 虽然这确实有所改善,但仍不能正常运行。添加显式 Close() 后,我经常在之后读取新数据,但并非总是如此。
  • 我尝试了与上述类似的测试,而单独的 ODBC 进程每秒更新一次相同的记录,并且显式启用了con1.Close() con2 在看到更新之前无需等待超过 3 毫秒价值。 (con1 上的 UPDATE 有时必须等待约 1 秒才能完成,但这并不影响 con2 必须等待查看结果的时间。)显然,您的环境中还有其他事情我没有考虑到.无意中启用了 ODBC 跟踪可能会减慢速度,但效果会更加一致。
  • 这不会是一个 ASP.NET 应用程序吧?
  • 不,它是一个 Windows 桌面应用程序,没有启用跟踪。我在两种情况下看到了这个问题。 1:更新记录并立即加载包含该记录的网格。 2:插入表格并关闭应用程序。另一个应用程序接管并且不能立即看到插入的数据。我可能别无选择,只能轮询数据并等待更改生效后再考虑完成。
【解决方案2】:

抛出一个想法 - 在 using 语句之后关闭连接或将 using 语句与外部 using 语句嵌套用于连接会做任何事情吗?我认为这个问题可能与非托管资源有关,或者 dispose 实现可能会触发某种强制更新。

【讨论】:

  • 我尝试关闭并重新打开所有连接,但没有任何改善。事实上,即使整个应用程序终止并快速读取不同的应用程序也会遇到同样的问题。这让我觉得它与 c# 代码无关,它是 ODBC 连接本身固有的东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多