Уведомление об изменении Oracle содержит недействительные действия
Настроить
Я создал консольное приложение для.NET 4.7.2 и установил пакет NuGet https://www.nuget.org/packages/Oracle.ManagedDataAccess/ версии 12.2.1100 (последняя / текущая), который устанавливает зависимость с двумя запросами для отслеживания изменений, внесенных в 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 строки с INSERT
+ UPDATE
для первого QueryId (63) и INSERT
+ UPDATE
для второго QueryId (64), так что теперь я могу отличить их.
Разделение командных зависимостей на несколько OracleDependency
классы или даже множественные связи приводят к одному и тому же результату.
Интересно, кто-нибудь знает, что здесь происходит?
2 ответа
Возможно, использование одного и того же экземпляра OracleDependency с двумя OracleCommand приводит к такому поведению.
В разделе замечаний в документации Oracle для AddCommandDependency говорится, что это возможно, но это не похоже на конфигурацию по умолчанию.
Я бы предложил использовать два отдельных экземпляра OracleDependency. Мы не знаем, как агрегация двух запросов выполняется внутренне, но я предполагаю, что ODP.NET каким-то образом объединяет два запроса в один, используя синтаксис, который не поддерживается в "гарантированном" режиме.
Это может привести к тому, что уведомление будет использовать режим "наилучшего возможного", который, как указано в документах, склонен к ложным срабатываниям.
Кажется, нет способа узнать, какой режим используется при использовании ODP.NET, но я думаю, что режим автоматически определяется из запроса, и ограничения на запросы для каждого режима описаны здесь.
попробуйте проверить QueryBasedNotification of OracleDependency.
По умолчанию это свойство истинно. Разработчики ODP.NET могут регистрировать свои запросы на уровне строк, а не только на уровне объекта, начиная с Oracle Data Provider для .NET версии 11.1 и Oracle Database11g выпуска 1 (11.1). Приложение получает уведомление только тогда, когда выбранная строка или строки Уведомления на основе запросов предоставляют разработчикам большую степень детализации для использования кэшированных данных на стороне клиента, поскольку они могут быть более конкретными в отношении того, о каких изменениях необходимо уведомлять приложение.