#c# #postgresql #npgsql
#c# #postgresql #npgsql
Вопрос:
Я пишу приложение, которое опрашивает postgresql DB для проверки новых строк, вставленных другим приложением. Большую часть времени все работает, но время от времени что-то «зависает». Даже если в базе данных существует более новая запись, приложение считывает вторую последнюю строку.
Опрос осуществляется следующим кодом
private async Task<ResultRow> RetreiveLastRow() {
ResultRow row = null;
var connectionString = "server=<ip>;user id=<user>;password=<pass>;database=<db name>";
using (var connection = new NpgsqlConnection(connectionString))
using (var command = connection.CreateCommand()) {
await connection.OpenAsync();
command.CommandText = "SELECT <fields> FROM <table> ORDER BY <field> DESC LIMIT 1";
using (var reader = await command.ExecuteReaderAsync()) {
if (await reader.ReadAsync()) {
row = <read row>;
}
}
connection.Close();
}
return row;
}
Метод, описанный выше, вызывается в цикле каждые ~ 100 мс.
while (!cancellationToken.IsCancellationRequested) {
try {
var lastRow = await RetreiveLastRow();
Logger.Trace($"Last row id = {lastRow.Id}");
// rest of code...
} catch (Exception e) {
Logger.Error(e, "Error");
}
await Task.Delay(TimeSpan.FromMilliseconds(100));
}
Я точно знаю, что в базе данных есть более новая запись. Я вижу это с помощью pgAdmin, но мое приложение не видит того, что я вижу.
Все возвращается в нормальное русло, когда в таблицу добавляется еще одна строка — приложение видит самые новые данные (за некоторое время). Через некоторое время, когда в таблицу добавляются новые записи, проблема появляется снова.
Я подозреваю, что результат запроса кэшируется драйвером и не обновляется из базы данных. Поэтому я попытался отключить опрос соединения, добавив «polling = false» в строку подключения (что должно отключить кэширование, если оно есть). Кажется, это решает проблему, но я не совсем уверен.
Действительно ли это проблема с кэшированием? Если это так, можно ли это решить, не отключая опрос соединения?
Комментарии:
1. В Npgsql нет никакого кэширования запросов — всякий раз, когда вы выполняете команду, она отправляется в базу данных и выполняется. Вы уверены, что ваша недавно вставленная строка не находится в незафиксированной транзакции (и поэтому еще не видна в других соединениях)?
2. Независимо от того, что вы делаете, может быть достигнуто лучше с помощью триггеров и Npgsql Wait(), а не опроса. Обратите внимание, что с помощью вашего метода вы можете пропустить строки, которые они вставляются быстро (т.Е. 2 строки в окне опроса).
3. Наконец, если вы хотите сохранить свой текущий дизайн, вам, вероятно, следует просто оставить одно соединение открытым в течение всего срока службы приложения и повторно использовать его, а не открывать заново. Вы также можете подготовить свою команду опроса для немного лучшей производительности.
4. Я не уверен, что это незафиксированная транзакция, но другое программное обеспечение (а именно pgAdmin) видит новую строку, поэтому я предполагаю, что она зафиксирована.
connection.Close()
не закрывает соединение, а просто возвращает его в пул, предоставляемый npgsql, поэтому текущий код должен извлекать выгоду из одного соединения. Ваше предложение использоватьWait
метод очень интересно. Я понятия не имел, что это возможно. Я обязательно попробую. Вопрос по-прежнему остается в силе: в чем может быть причина того, что мой способ иногда не работает?5. Просто чтобы убедиться, что новая строка не добавлена из нормального pgadmin, который используется для проверки того, что строка была вставлена, не так ли? В противном случае это снова может быть простым вопросом незафиксированной транзакции. Если нет, и ваш pgadmin видит новую строку, а ваше приложение Npgsql — нет, то, скорее всего, есть какая-то проблема с кодом вашего приложения — SQL-запрос или что-то еще (чего я не могу знать, не видя весь код и т. Д.)