Как уменьшить время, необходимое Progress OpenEdge OdbcCommand с использованием транзакции ReadCommitted для сообщения о блокировке в C#?

Мы пишем подпрограмму, которая либо возвращает редактируемый объект, либо объект состояния, который говорит, что базовая запись заблокирована.

Мы используем C# и .NET Framework 4.8 с драйвером ODBC Progress OpenEdge для базы данных OpenEdge. Запись может быть заблокирована устаревшим кодом ABL, поэтому мы хотим проверить транзакцию ReadCommitted, чтобы убедиться, что для нас безопасно начинать ее редактирование.

Функционально код работает нормально, делая именно то, что мы от него ожидаем. Когда базовая запись не заблокирована, она возвращает объект за миллисекунды; когда он заблокирован, он возвращает объект, описывающий заблокированный статус записи.

Но когда базовая запись действительно заблокирована, требуется более 15 секунд, чтобы вернуться с ожидаемой «ОШИБКОЙ [HY000] [DataDirect] [ODBC Progress OpenEdge Wire Protocol driver] [OPENEDGE] Не удалось получить блокировку записи для записи из таблицы PUB.i -мст."

Я попытался уменьшить значение CommandTimeout, но только это (в конце концов, поскольку я уменьшаю его постепенно) в конечном итоге меняет сбой на ошибку тайм-аута.

Есть ли какой-либо параметр более низкого уровня для управления тем, сколько времени требуется ODBC или OpenEdge для ожидания освобождения блокировки перед сбоем?

Вот код:

        public static dynamic ReadOdbcForEdit(OdbcConnection connection, string type, string criteria, string domain,
            string parentClass, string application)
        {
            connection.Open();
            var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted);
            Type objectType = Object.GetJohnstonType(parentClass + type, domain, application);
            var tempObj = Activator.CreateInstance(objectType);

            try
            {
                var odbcCommand = new OdbcCommand(criteria)
                {
                    Connection = connection,
                    Transaction = transaction,
                    CommandTimeout = 30
                };

                var reader = odbcCommand.ExecuteReader();

                while (reader.Read())
                {

                    foreach (var property in tempObj.GetType().GetProperties())
                    {

                        var propertyType = property.PropertyType;
                        var propertyName = property.Name;

                        if (propertyType.IsArray ||
                            propertyType.IsGenericType &&
                            propertyType.GetGenericTypeDefinition() == typeof(List<>))
                        {
                            continue;
                        }

                        try
                        {
                            if (reader[propertyName].GetType() != typeof(DBNull))
                            {
                                property.SetValue(tempObj, reader[propertyName]);
                            }
                        }
                        catch (Exception e)
                        {
                            Logging.Message($"Could not fill {propertyName} from database column");
                            Logging.Exception(e);
                        }
                    }

                } 

                return tempObj;
            }
            catch (Exception e)
            {
                var openRecordStatus = new OpenRecordStatus
                {
                    StatusCode = e.HResult,
                    StatusMessage = e.Message
                };
                return openRecordStatus;
            }
        }

person J. Hochberg    schedule 01.11.2019    source источник


Ответы (1)


Возможно, вы захотите настроить -SQLLockWaitTimeout

https://knowledgebase.progress.com/articles/Article/What-is-the-SQLLockWaitTimeout-Parameter

Параметр -SQLLockWaitTimeout используется для определения количества секунд ожидания при возникновении конфликта блокировки. По умолчанию 5 секунд.

Это значение применяется ко всем конфликтам блокировок, с которыми сталкиваются приложения SQL. Таким образом, установка, которая получает много конфликтов блокировки (выполняет много обновлений), должна рассмотреть влияние изменения этого параметра.

Для более старых версий Progress (до 11.4): https://knowledgebase.progress.com/articles/Article/P123923

Переменная среды PROSQL_LOCKWAIT_TIMEOUT была введена в версии 9.1D06 и используется для ограничения того, как долго клиент будет ожидать запись, имеющую общую или монопольную блокировку. Этот параметр не действует и не требуется для клиента SQL с уровнем изоляции READ UNCOMMITTED, поскольку он будет считывать запись, для которой установлена ​​общая или монопольная блокировка.

Переменная среды PROSQL_LOCKWAIT_TIMEOUT позволяет определить, как долго клиенты SQL будут ждать в очереди блокировки конкретной записи. Переменная среды должна присутствовать перед запуском посредника и применяется к каждому SQL-соединению посредника.

Минимальное значение тайм-аута по умолчанию составляет пять секунд (DFLT_LOCKWAIT-TIMEOUT). Максимальное время ожидания ограничено 32-битным целым числом, равным 4 294 967 295 секунд или 1 193 046,5 часов.

Эту переменную среды можно задать перед запуском брокера баз данных или AdminServer. Например, чтобы установить его на 30 секунд:

UNIX: PROSQL_LOCKWAIT_TIMEOUT=30 ; экспорт PROSQL_LOCKWAIT_TIMEOUT

Windows: Панель управления -> Система -> вкладка «Дополнительно» -> Переменные среды -> Системные переменные. Добавьте новую переменную.

В OpenEdge 11.4 и более поздних версиях есть параметр запуска -SQLLockWaitTimeout, который можно использовать для достижения той же цели, что и переменную среды. См. статью: 000064602, Что такое параметр -SQLLockWaitTimeout? для получения дополнительной информации.

person Tom Bascom    schedule 04.11.2019
comment
К сожалению, это, вероятно, не вариант для нашей среды, но я проконсультируюсь с нашим администратором баз данных OpenEdge. Спасибо, что заглянули! - person J. Hochberg; 05.11.2019
comment
Просто любопытно, а почему бы и нет? Кажется, это именно то, о чем вы просите, поэтому я не должен понимать какую-то часть вашего требования. - person Tom Bascom; 06.11.2019
comment
Мы перечитали ответы и справочные статьи базы знаний и поняли, что это относится только к SQL, так что это действительно похоже на правильное решение. Меня беспокоит только то, что текущее время отклика больше порядка 15 секунд, и поэтому я не уверен, действительно ли изменение параметра принесет пользу. Не больно попробовать. :) - person J. Hochberg; 06.11.2019