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

如何减少Progress OpenEdge OdbcCommand使用ReadCommitted事务报告C#中的锁所需的时间?,c#,odbc,openedge,progress-db,datadirect,C#,Odbc,Openedge,Progress Db,Datadirect,我们正在编写一个例程,它要么返回一个可编辑对象,要么返回一个表示底层记录已锁定的状态对象 我们正在对OpenEdge数据库使用C#和.NET Framework 4.8以及Progress OpenEdge ODBC驱动程序。记录可能会被遗留ABL代码锁定,这就是为什么我们要检查ReadCommitted事务,以确定开始编辑它是否安全 从功能上讲,代码运行良好,完全符合我们的预期。当底层记录未锁定时,它会在毫秒内返回对象;当它被锁定时,它返回一个描述记录锁定状态的对象 但当底层记录确实被锁定时,

我们正在编写一个例程,它要么返回一个可编辑对象,要么返回一个表示底层记录已锁定的状态对象

我们正在对OpenEdge数据库使用C#和.NET Framework 4.8以及Progress OpenEdge ODBC驱动程序。记录可能会被遗留ABL代码锁定,这就是为什么我们要检查ReadCommitted事务,以确定开始编辑它是否安全

从功能上讲,代码运行良好,完全符合我们的预期。当底层记录未锁定时,它会在毫秒内返回对象;当它被锁定时,它返回一个描述记录锁定状态的对象

但当底层记录确实被锁定时,需要15秒以上的时间才能返回预期的“错误[HY000][DataDirect][ODBC Progress OpenEdge Wire Protocol driver][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;
            }
        }
public静态动态ReadOdbcForEdit(OdbcConnection连接、字符串类型、字符串条件、字符串域、,
字符串父类,字符串应用程序)
{
connection.Open();
var事务=connection.BeginTransaction(IsolationLevel.ReadCommitted);
类型objectType=Object.getjohnstotype(父类+类型、域、应用程序);
var tempObj=Activator.CreateInstance(objectType);
尝试
{
var odbcCommand=新的odbcCommand(标准)
{
连接=连接,
交易=交易,
CommandTimeout=30
};
var reader=odbcCommand.ExecuteReader();
while(reader.Read())
{
foreach(tempObj.GetType().GetProperties()中的var属性)
{
var propertyType=property.propertyType;
var propertyName=property.Name;
如果(propertyType.IsArray||
propertyType.IsGenericType&&
propertyType.GetGenericTypeDefinition()==typeof(列表))
{
继续;
}
尝试
{
if(reader[propertyName].GetType()!=类型of(DBNull))
{
SetValue(tempObj,reader[propertyName]);
}
}
捕获(例外e)
{
Message($“无法从数据库列填充{propertyName}”);
例外情况(e);
}
}
} 
返回tempObj;
}
捕获(例外e)
{
var openRecordStatus=新的openRecordStatus
{
状态代码=e.HResult,
StatusMessage=e.Message
};
返回openRecordStatus;
}
}

您可能需要调整-SQLLockWaitTimeout

-SQLLockWaitTimeout参数用于标识 发生锁冲突时等待的秒数。默认值为5秒

此值适用于SQL遇到的所有锁冲突 应用。所以一个安装会有很多锁冲突 (有很多更新)会考虑改变的影响吗? 这个参数

对于较旧版本的Progress(11.4之前的版本):

PROSQL_LOCKWAIT_TIMEOUT环境变量是在中引入的 9.1D06,用于限制客户端等待具有共享或独占锁定的记录的时间。此设置不可用 隔离级别为的SQL客户端不需要 读取未提交,因为它将读取具有共享或 对它的独占锁

PROSQL_LOCKWAIT_TIMEOUT环境变量使您能够 确定SQL客户端将在锁定队列中等待 特别记录。环境变量必须出现在 代理将启动并应用于的每个SQL连接 经纪人

最小超时值默认为5秒 (DFLT_锁定等待超时)。最大超时值限制为 4294967295秒或1193046.5小时的32位整数值

可以在启动数据库之前设置此环境变量 代理或管理员服务器。例如,要将其设置为30秒:

UNIX:PROSQL_LOCKWAIT_TIMEOUT=30;导出PROSQL\u锁定等待\u超时

Windows:控制面板->系统->高级选项卡->环境 变量->系统变量。添加一个新变量

在OpenEdge 11.4及更高版本中,有一个-SQLLockWaitTimeout启动 参数,该参数可用于实现与 环境变量。参见文章:000064602,什么是 -SQLLockWaitTimeout参数?有关更多信息,请参阅


不幸的是,对于我们的环境来说,这可能不是一个选项,但我将咨询OpenEdge DBA。谢谢你的调查!只是好奇,但为什么这不是一个选择呢?这似乎正是你所要求的,所以我一定不理解你的要求。我们已经阅读了回复