Как уменьшить время, необходимое Progress OpenEdge OdbcCommand, использующему транзакцию ReadCommitted, чтобы сообщить о блокировке в C #? - PullRequest
1 голос
/ 01 ноября 2019

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

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

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

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

Я попытался уменьшить значение 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;
            }
        }

1 Ответ

1 голос
/ 05 ноября 2019

Возможно, вы захотите настроить -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? для дополнительной информации.

...