为什么 OdbcCommand.ExecuteScalar() 抛出 AccessViolationException?

发布于 2024-07-07 01:04:48 字数 1969 浏览 3 评论 0原文

我有一段代码旨在从数据库表中提取文本描述并将其保存到文本文件中。 它看起来像这样 (C# .NET):

        OdbcCommand getItemsCommand = new OdbcCommand("SELECT ID FROM ITEMS", databaseConnection);
        OdbcDataReader getItemsReader = getItemsCommand.ExecuteReader();
        OdbcCommand getDescriptionCommand = new OdbcCommand("SELECT ITEMDESCRIPTION FROM ITEMS WHERE ID = ?", databaseConnection);
        getDescriptionCommand.Prepare();
        while (getItemsReader.Read())
        {
            long id = getItemsReader.GetInt64(0);
            String outputPath = "c:\\text\\" + id + ".txt";
            if (!File.Exists(outputPath))
            {
                getDescriptionCommand.Parameters.Clear();
                getDescriptionCommand.Parameters.AddWithValue("id", id);
                String description = (String)getDescriptionCommand.ExecuteScalar();
                StreamWriter outputWriter = new StreamWriter(outputPath);
                outputWriter.Write(description);
                outputWriter.Close();
            }
        }
        getItemsReader.Close();

此代码已成功将一部分数据保存到 .txt 文件,但对于许多行,在以下行中抛出 AccessViolationException:

                String description = (String)getDescriptionCommand.ExecuteScalar();

异常文本为“尝试读取或写入受保护的数据”这通常表明其他内存已损坏”。

程序通常会在表的相同行上抛出异常,但它似乎并不是 100% 一致。 有时,过去抛出异常的数据会突然起作用。

有些人无疑想知道为什么我不直接在 getItemsCommand 中 SELECT ID, ITEMDESCRIPTION FROM ITEMS 并跳过第二个查询。 实际上,我最初就是这样做的,并且在使用 getItemsCommand.GetString() 时遇到了同样的错误。 我担心数据集可能占用了太多内存,这可能导致了错误。 所以我决定尝试一下这个方法,看看是否有帮助。 事实并非如此。 有谁知道为什么会发生这种情况?

顺便说一下,ID 是 INT,ITEMDESCRIPTION 是 VARCHAR(32000) 列。 如果有什么区别的话,数据库是 Borland Interbase 6.0(恶心!)

编辑:在描述抛出异常的位置时,我给出了错误的行! 啊啊!! 现在修好了。 另外,我已经尝试过到目前为止建议的方法,但它们没有帮助。 但是,我发现只有数据库中非常旧的记录才会导致此错误,这很奇怪。 如果我将查询更改为仅提取最近 5 年插入的记录,则不会有问题。 有人向我建议这可能是编码转换问题或类似的问题?

更新:解决了。 事实证明,该问题是我们不太可靠的数据库软件的 ODBC 驱动程序中的错误。 与其他驱动程序的解决方法解决了该问题。

I have a block of code intended to pull text descriptions from a database table and save them to a text file. It looks like this (C# .NET):

        OdbcCommand getItemsCommand = new OdbcCommand("SELECT ID FROM ITEMS", databaseConnection);
        OdbcDataReader getItemsReader = getItemsCommand.ExecuteReader();
        OdbcCommand getDescriptionCommand = new OdbcCommand("SELECT ITEMDESCRIPTION FROM ITEMS WHERE ID = ?", databaseConnection);
        getDescriptionCommand.Prepare();
        while (getItemsReader.Read())
        {
            long id = getItemsReader.GetInt64(0);
            String outputPath = "c:\\text\\" + id + ".txt";
            if (!File.Exists(outputPath))
            {
                getDescriptionCommand.Parameters.Clear();
                getDescriptionCommand.Parameters.AddWithValue("id", id);
                String description = (String)getDescriptionCommand.ExecuteScalar();
                StreamWriter outputWriter = new StreamWriter(outputPath);
                outputWriter.Write(description);
                outputWriter.Close();
            }
        }
        getItemsReader.Close();

This code has successfully saved a portion of the data to .txt files, but for many rows, an AccessViolationException is thrown on the following line:

                String description = (String)getDescriptionCommand.ExecuteScalar();

The Exception text is "Attempted to read or write protected memory. This is often an indication that other memory is corrupt".

The program will usually throw the exception on the same rows of the table, but it doesn't appear to be 100% consistent. Sometimes data that had thrown the exception in the past will suddenly work.

Some people are undoubtedly wondering why I didn't just SELECT ID, ITEMDESCRIPTION FROM ITEMS in the getItemsCommand and skip the second query. Actually, I did it that way initially, and I was encountering the same error with getItemsCommand.GetString(). I was afraid that perhaps the dataset was taking up too much memory and maybe that was causing the error. So I decided to try this method to see if it would help. It didn't. Does anyone know why this might be happening?

By the way, ID is an INT and ITEMDESCRIPTION is a VARCHAR(32000) column. If it makes any difference, the database is Borland Interbase 6.0 (Ick!)

EDIT: I gave the wrong line when describing where the exception was being thrown!! ARGH!! Fixed now. Also, I've tried the things suggested so far, but they didn't help. However, I found that only very old records in the database were causing this error, which is strange. If I change the query to only pull records inserted in the last 5 years, there are no problems. Someone suggested to me this might be an encoding conversion problem or something like that?

Update: Solved it. The problem turned out to be a bug in the ODBC driver for our not-very-reliable database software. A workaround with other drivers fixed the problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

九歌凝 2024-07-14 01:04:48

这可能是您正在使用的 ODBC 驱动程序中的错误。 是什么司机? 你的连接字符串是什么?

It could be a bug in the ODBC driver you are using. What driver is it? What is your connection string?

可是我不能没有你 2024-07-14 01:04:48

这里是黑暗中的一枪......

尝试执行你的阅读器,保存你的结果(可能在数组或列表中),并确保在执行或准备下一个命令之前关闭阅读器。 您甚至可能想走极端,将 getItemsCommand 构造放入 using 块中,这样您就知道在执行下一个命令之前它没有打开资源...

A shot in the dark here...

Try executing your reader, saving your result (maybe in an array or list), and making sure the reader is closed before executing or preparing the next command. You may even want to go extreme and put your getItemsCommand construction inside a using block so you know that it has no resources open before you execute your next command...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文