简体   繁体   English

如何减少使用 ReadCommitted 事务的 Progress OpenEdge OdbcCommand 报告 C# 中的锁定所需的时间?

[英]How do I decrease the time it takes for a Progress OpenEdge OdbcCommand using ReadCommitted transaction to report a lock in C#?

We're writing a routine which either returns an editable object, or a status object that says the underlying record is locked.我们正在编写一个例程,它要么返回可编辑的 object,要么返回表示底层记录已锁定的状态 object。

We're using C# and .NET Framework 4.8 with the Progress OpenEdge ODBC driver against an OpenEdge database.我们将 C# 和 .NET Framework 4.8 与 Progress OpenEdge ODBC 驱动程序一起用于 OpenEdge 数据库。 The record might be locked by legacy ABL code, which is why we want to check with a ReadCommitted transaction to see if it's safe for us to start editing it.记录可能被遗留 ABL 代码锁定,这就是为什么我们要检查 ReadCommitted 事务以查看我们是否可以安全地开始编辑它。

Functionally, the code works fine, doing exactly what we expect it to do.从功能上讲,代码运行良好,完全符合我们的预期。 When the underlying record is not locked, it returns the object in a matter of milliseconds;当底层记录未锁定时,它会在几毫秒内返回 object; when it's locked, it returns an object that describes the locked status of the record.当它被锁定时,它返回一个描述记录锁定状态的 object。

But when the underlying record is indeed locked it takes upwards of 15 seconds to return with the expected "ERROR [HY000] [DataDirect][ODBC Progress OpenEdge Wire Protocol driver][OPENEDGE]Failure getting record lock on a record from table PUB.i-mst."但是,当底层记录确实被锁定时,需要 15 秒以上才能返回预期的“错误 [HY000] [DataDirect][ODBC Progress OpenEdge Wire Protocol driver][OPENEDGE]Failure getting record lock on a record from table PUB.i -mst。”

I have tried decreasing the CommandTimeout value, but that only (eventually, as I decrease it incrementally) ultimately changes the failure to a timeout error.我曾尝试减小 CommandTimeout 值,但这只是(最终,随着我逐渐减小它)最终将失败更改为超时错误。

Is there some lower-level setting to control how long either ODBC or OpenEdge takes to wait for a lock to be released before failing?是否有一些较低级别的设置来控制 ODBC 或 OpenEdge 在失败前等待锁定释放的时间?

Here's the code:这是代码:

        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;
            }
        }

You probably want to adjust -SQLLockWaitTimeout您可能想要调整 -SQLLockWaitTimeout

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

The -SQLLockWaitTimeout parameter is used to identify the number of seconds to wait when a lock conflict occurs. -SQLLockWaitTimeout 参数用于标识发生锁冲突时要等待的秒数。 The default is 5 seconds.默认值为 5 秒。

This value applies to all lock conflicts experienced by SQL applications.此值适用于 SQL 应用程序遇到的所有锁冲突。 So an installation that gets a lot of lock conflicts (does a lot of updating) would want to consider the impact of changing this parameter.因此,发生大量锁冲突(进行大量更新)的安装需要考虑更改此参数的影响。

For older versions of Progress (prior to 11.4): https://knowledgebase.progress.com/articles/Article/P123923对于旧版本的 Progress(11.4 之前): https://knowledgebase.progress.com/articles/Article/P123923

The PROSQL_LOCKWAIT_TIMEOUT environment variable was introduced in 9.1D06 and is used to limit how long a client will wait for a record that has a share or exclusive lock against it. PROSQL_LOCKWAIT_TIMEOUT 环境变量是在 9.1D06 中引入的,用于限制客户端等待对其具有共享或排他锁的记录的时间。 This setting does not effect and is not needed for an SQL Client with an isolation level of READ UNCOMMITTED, because it will read a record that has a share or exclusive lock against it.对于隔离级别为 READ UNCOMMITTED 的 SQL 客户端,此设置不起作用且不需要,因为它将读取对其具有共享或排他锁的记录。

The PROSQL_LOCKWAIT_TIMEOUT environment variable enables one to determine how long SQL clients will wait in a lock queue for a particular record. PROSQL_LOCKWAIT_TIMEOUT 环境变量使人们能够确定 SQL 客户端将在锁定队列中等待特定记录的时间。 The environment variable must be present before a broker is started and is applied to every SQL connection of the broker.环境变量必须在代理启动之前存在,并应用于代理的每个 SQL 连接。

The minimum time-out value is the default of five seconds (DFLT_LOCKWAIT-TIMEOUT).最小超时值是五秒的默认值 (DFLT_LOCKWAIT-TIMEOUT)。 The maximum time-out value is limited to a 32-bit integer value of 4,294,967,295 seconds or 1,193,046.5 hours.最大超时值限制为 32 位 integer 值 4,294,967,295 秒或 1,193,046.5 小时。

This environment variable can be set prior to starting the database broker or AdminServer.可以在启动数据库代理或 AdminServer 之前设置此环境变量。 For example, to set it to 30 seconds:例如,将其设置为 30 秒:

UNIX: PROSQL_LOCKWAIT_TIMEOUT=30; UNIX:PROSQL_LOCKWAIT_TIMEOUT=30; export PROSQL_LOCKWAIT_TIMEOUT导出 PROSQL_LOCKWAIT_TIMEOUT

Windows: Control Panel -> System -> Advanced tab -> Environment Variables -> System Variables. Windows:控制面板 -> 系统 -> 高级选项卡 -> 环境变量 -> 系统变量。 Add a new variable.添加一个新变量。

In OpenEdge 11.4 and later there is a -SQLLockWaitTimeout startup parameter that can be used to accomplish the same goal as the environment variable.在 OpenEdge 11.4 及更高版本中,有一个 -SQLLockWaitTimeout 启动参数可用于实现与环境变量相同的目标。 See article: 000064602, What is the -SQLLockWaitTimeout Parameter?请参阅文章:000064602,什么是 -SQLLockWaitTimeout 参数? for additional information.了解更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM