首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ODAC似乎在缓存表模式?

ODAC似乎在缓存表模式?
EN

Stack Overflow用户
提问于 2013-05-31 14:21:15
回答 2查看 1.1K关注 0票数 1

我正在针对Oracle11Express数据库使用Oracle的ODAC.NET进行.NET 3.5项目,我看到了无法解释的行为(而且似乎无法解释)。

ODAC应该是最新的,我三天前才把它拔出来,但是版本如下:

  • Oracle.DataAccess.dll版本2.112.3.0 (第5版)
  • oci.dll (即时客户端) 11.2.0.1版

我有一张桌子,伙计们,它有三栏:

  • ID
  • FirstName
  • LastName

在代码中,我使用OracleCommand.ExecuteNonQuery运行一个ALTER命令,向表中添加一个名为"MIDDLE_NAME“的新列。这个命令成功了。如果我使用Oracle SQL Developer查看表,就会显示这些列。一切都很好。

现在,如果我在执行alter之后运行了使用OracleCommand.ExecuteReader命令文本的SELECT * FROM People,那么我得到的数据只有3列,而不是4列!

下面是再现问题的代码:

代码语言:javascript
复制
public void FieldTest()
{
    var sql1 = "CREATE TABLE People (" +
        "ID NUMBER PRIMARY KEY, " +
        "FirstName NVARCHAR2 (200), " +
        "LastName NVARCHAR2 (200) NOT NULL)";

    var sql2 = "ALTER TABLE People " +
        "ADD Middle_Name NUMBER";

    var sql3 = "SELECT * FROM People";

    var sql4 = "SELECT column_name FROM all_tab_cols WHERE table_name = 'PEOPLE'";

    var cnInfo = new OracleConnectionInfo("192.168.10.246", 1521, "XE", "system", "password");
    var connectionString = BuildConnectionString(cnInfo);

    using (var connection = new OracleConnection(connectionString))
    {
        connection.Open();

        using (var create = new OracleCommand(sql1, connection))
        {
            create.ExecuteNonQuery();
        }

        using (var get = new OracleCommand(sql3, connection))
        {
            using (var reader = get.ExecuteReader())
            {
                Debug.WriteLine("Columns: " + reader.FieldCount);
                // outputs 3, which is right
            }
        }

        using (var alter = new OracleCommand(sql2, connection))
        {
            alter.ExecuteNonQuery();
        }

        using (var get = new OracleCommand(sql3, connection))
        {
            using (var reader = get.ExecuteReader())
            {
                Debug.WriteLine("Columns: " + reader.FieldCount);
                // outputs 3, which is *wrong* <---- Here's the problem
            }
        }

        using (var cols = new OracleCommand(sql4, connection))
        {
            using (var reader = cols.ExecuteReader())
            {
                int count = 0;

                while (reader.Read())
                {
                    count++;
                    Debug.WriteLine("Col: " + reader.GetString(0));
                }
                Debug.WriteLine("Columns: " + count.ToString());
                // outputs 4, which is right
            }
        }
    }
}

我尝试过一些方法来阻止这种行为,但没有一个能让我回到第四栏:

  • 我关闭连接并重新打开它
  • 我使用新的OracleConnection来表示SELECT而不是ALTER
  • 我使用相同的OracleConnection用于SELECTALTER
  • 我使用新的OracleCommand来表示SELECT而不是ALTER
  • 我使用相同的OracleCommand用于SELECTALTER
  • 我在PurgeStatementCacheALTER之间的连接上调用SELECT
  • 我在FlushCacheALTER之间的连接上调用SELECT
  • 我显式地CloseDispose用于ALTERSELECTOracleCommandOracleConnection (相对于using块)
  • 重新启动调用PC和承载Oracle数据库的PC。

如果我通过执行SELECT * FROM all_tab_cols来查看列列表,就会看到新的列。

唯一可靠的工作似乎是关闭应用程序并重新启动它(这是从一个单元测试,但它是关闭和重新启动测试主机)。那我就得到了第四栏。有时,我可以使用断点和重新执行查询,第4列就会出现,但是没有任何代码的直接执行(这意味着不设置断点并将执行点向上移动)特别可重复的内容。

ODAC的核心内容似乎是缓存表的模式,但我可以弄清楚是什么、为什么或如何防止它。有人对此有任何经验,或者想过我该如何预防?

EN

回答 2

Stack Overflow用户

发布于 2017-01-25 22:45:45

我知道这个答案是几年后才出现的,但是如果新的读者在缓存方面遇到问题,请尝试设置:

元数据池= false,自调优= False和语句缓存大小=0

...in连接字符串。请记住,这样做会对性能产生影响。

https://docs.oracle.com/database/122/ODPNT/featConnecting.htm#GUID-0CFEB161-68EF-4BC2-8943-3BDFFB878602

票数 2
EN

Stack Overflow用户

发布于 2013-05-31 15:58:26

也许发布一些您的C#代码。下面是一个按照预期运行的测试,这意味着我可以在添加新列之后立即看到它。这是使用odp 11.2 rel 5命中11g db,使用4.0框架:

测试表是:

代码语言:javascript
复制
CREATE TABLE T1
(
  DTE  DATE default sysdate
);

每次运行以下C#代码后,删除并重新创建它(有点脏,但无论如何):

代码语言:javascript
复制
string connStr = "User Id=xxx;Password=yyy;Data Source=my11gDb;";
using (OracleConnection con = new OracleConnection(connStr))
{
    string s = "ALTER TABLE T1 ADD (added_col VARCHAR2(10))";
    using (OracleCommand cmd = new OracleCommand(s, con))
    {
        con.Open();
        cmd.ExecuteNonQuery();

        string s2 = "select column_name from all_tab_columns where table_name = 'T1'";
        //con.FlushCache(); // doesn't seem to matter, works with or without

        using (OracleCommand cmd2 = new OracleCommand(s2, con))
        {
            OracleDataReader rdr = cmd2.ExecuteReader();

            for (int i = 0; rdr.Read(); i++)
            {
                Console.WriteLine("Column {0} => {1}",i+1,rdr.GetString(0));
            }
            rdr.Close();
        }
    }
}

输出:

代码语言:javascript
复制
Column 1 => DTE
Column 2 => ADDED_COL

编辑:啊,好吧,我明白你在说什么,它看起来像语句缓存。我反复尝试将缓存大小更改为0(在康涅狄格字符串中,使用“语句缓存Size=0"),并尝试了cmd.AddToStatementCache = false,但这些方法都不起作用。

工作的一件事是使用一个稍微不同的字符串,比如添加一个空格。我知道这是个黑客,但这是我唯一能为我工作的。

试试你的例子,用:

代码语言:javascript
复制
var sql3 = "SELECT * FROM People";
var sql5 = "SELECT * FROM People "; // note extra space

并在添加列之前使用sql3,在添加列后使用sql5。

希望这有帮助

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16859567

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档