3

设置

我创建了一个针对 .NET 4.7.2 的控制台应用程序,并安装了 NuGet 包Oracle.ManagedDataAccess版本 12.2.1100(最新/当前),它设置了一个依赖项,其中包含 2 个查询来监视对 所做的更改MYTABLE,两个查询都有不同的 WHERE -条款。

我要连接的 Oracle 数据库服务器在 localhost 上运行,版本为 12.2.0.1.0。

在侦听通知的控制台应用程序旁边,我使用 Oracle SQL Developer (v18.1.0.095) 将记录实际插入或更新到 MYTABLE 以强制通知。

代码

using (var connection = new OracleConnection("Data Source=//localhost:1521/ORCL;Persist Security Info=True;User ID=SYSTEM;Password=password"))
{
    OracleDependency.Port = 3005;

    var dependency = new OracleDependency();
    dependency.OnChange += (sender, eventArgs) =>
    {
        Console.WriteLine($"Change count: {eventArgs.Details.Rows.Count}");

        // Columns in row: string ResourceName, int Info, string Rowid, long QueryId
        foreach (DataRow row in eventArgs.Details.Rows)
        {
            var resourceName = (string)row["ResourceName"];
            var info = (OracleNotificationInfo)row["Info"];
            var rowId = (string)row["rowid"];
            var queryId = (long)row["QueryId"];

            Console.WriteLine($"{queryId} {info} {rowId} {resourceName}");
        }
    };

    connection.Open();

    var command1 = new OracleCommand("SELECT * FROM MYTABLE WHERE NAME = 'N1'", connection);
    dependency.AddCommandDependency(command1);
    command1.Notification.IsNotifiedOnce = false;
    command1.AddRowid = true;
    command1.ExecuteNonQuery();

    var command2 = new OracleCommand("SELECT * FROM MYTABLE WHERE NAME = 'N2'", connection);
    dependency.AddCommandDependency(command2);
    command2.Notification.IsNotifiedOnce = false;
    command2.AddRowid = true;
    command2.ExecuteNonQuery();

    Console.ReadKey();
}

行为

一旦我在一个事务中触发多个命令依赖项,我就会在通知中获得两倍的事件行,并且无法再区分触发它的 queryid。

在一个事务中运行此查询:

INSERT INTO MYTABLE (NAME) VALUES ('N1');

输出:

Change count: 1
63 Insert AAAR6CAABAAALohABJ SYSTEM.MYTABLE

在一个事务中运行此查询:

INSERT INTO MYTABLE (NAME) VALUES ('N2');

输出:

Change count: 1
64 Insert AAAR6CAABAAALohABK SYSTEM.MYTABLE

但是,在一个事务中运行此查询时:

INSERT INTO MYTABLE (NAME) VALUES ('N1');
INSERT INTO MYTABLE (NAME) VALUES ('N2');

我得到这个输出:

Change count: 4
63 Insert AAAR6CAABAAALohABH SYSTEM.MYTABLE
63 Insert AAAR6CAABAAALohABI SYSTEM.MYTABLE
64 Insert AAAR6CAABAAALohABH SYSTEM.MYTABLE
64 Insert AAAR6CAABAAALohABI SYSTEM.MYTABLE

虽然我期望:

Change count: 2
63 Insert AAAR6CAABAAALohABH SYSTEM.MYTABLE
64 Insert AAAR6CAABAAALohABI SYSTEM.MYTABLE

此外,当我执行INSERT触发第一个命令和UPDATE触发第二个命令的操作时,我得到 4 行,第一个 QueryId (63) 和+INSERT用于第二个 QueryId (64),所以现在我可以区分它们了。UPDATEINSERTUPDATE

将命令依赖关系分离到多个OracleDependency类甚至多个连接会导致相同的结果。

我想知道是否有人知道这里发生了什么?

4

2 回答 2

0

也许将相同的OracleDependency实例与两个OracleCommand一起使用会导致这种行为。

Oracle 文档AddCommandDependency备注部分说这是可能的,但它似乎不是默认配置。

我建议使用两个单独的 OracleDependency实例。我们不知道这两个查询的聚合是如何在内部完成的,但我猜可能 ODP.NET 以某种方式将这两个查询聚合为一个,使用“保证”模式下不支持的语法。

这可能会导致通知使用“尽力而为”模式,文档中说明该模式容易出现误报。

似乎没有办法知道在使用 ODP.NET 时使用哪种模式,但我猜想该模式是从查询中自动检测到的,并且每种模式的查询约束都记录在此处

于 2018-06-24T20:05:40.563 回答
0

尝试检查 OracleDependency 的 QueryBasedNotification。

默认情况下,此属性为 true。ODP.NET 开发人员可以在行级别注册他们的查询,而不仅仅是对象级别,从 Oracle Data Provider for .NET 版本 11.1 和 Oracle Database 11g 版本 1(11.1) 开始。应用程序仅在选定的行或多行时收到通知change.Query - 基于通知的通知为开发人员使用客户端缓存数据提供了更多粒度,因为他们可以更具体地说明应用程序需要通知哪些更改

于 2021-05-05T01:31:04.813 回答