Progress 11.7.5中UNDO释放类实例BUFFER的阻止方法咨询
TestClass内部包含BUFFER变量,构造函数执行后BUFFER处于可用状态。但执行任意UNDO或UNDO, THROW...语句后,类实例其他部分保持完整,唯独BUFFER变为NOT AVAILABLE。在测试代码中,第二个事务内的iValue = oTestClass:Value.会因BUFFER不可用抛出错误,使用版本为Progress 11.7.5,需阻止该BUFFER被RELEASE的操作。
Progress中,类实例的BUFFER会与执行FIND操作所在的事务绑定。当事务执行UNDO时,系统会自动释放该事务关联的所有BUFFER资源——即便BUFFER是类实例的成员,只要它在事务内被定位过,UNDO后就会进入不可用状态。你的场景中,Singleton的TestClass实例跨事务复用,第一次事务UNDO后BUFFER被释放,第二次访问属性自然报错。
以下几种方法可解决该问题:
方法1:每次访问属性时重新定位BUFFER
将FIND逻辑从构造函数移至Value属性的GET方法,每次访问属性时重新获取BUFFER数据,不受之前事务UNDO的影响:
BLOCK-LEVEL ON ERROR UNDO, THROW. CLASS TestClass: DEF PRIVATE BUFFER MyTable_This FOR MyTable. DEF PRIVATE VAR i_rowid AS ROWID NO-UNDO. DEF PUBLIC PROPERTY Value AS INT NO-UNDO GET: FIND FIRST MyTable_This WHERE ROWID(MyTable_This) = i_rowid NO-LOCK. RETURN MyTable_This.Value. END. CONSTRUCTOR PUBLIC TestClass(i_rROWID AS ROWID): i_rowid = i_rROWID. END. END.
方法2:缓存BUFFER数据到类变量
在构造函数中FIND数据后,将需要的字段值复制到类的私有变量,属性直接访问变量而非BUFFER,彻底脱离对BUFFER的依赖:
BLOCK-LEVEL ON ERROR UNDO, THROW. CLASS TestClass: DEF PRIVATE VAR i_value AS INT NO-UNDO. DEF PUBLIC PROPERTY Value AS INT NO-UNDO GET: RETURN i_value. END. CONSTRUCTOR PUBLIC TestClass(i_rROWID AS ROWID): DEF BUFFER MyTable_Temp FOR MyTable. FIND FIRST MyTable_Temp WHERE ROWID(MyTable_Temp) = i_rROWID NO-LOCK. i_value = MyTable_Temp.Value. END. END.
该方法适合数据变更频率低的场景,可避免重复查询;若需实时数据,优先选择方法1。
方法3:用独立事务初始化BUFFER
在构造函数中使用独立的小事务执行FIND操作,确保BUFFER的生命周期不受外部事务影响:
BLOCK-LEVEL ON ERROR UNDO, THROW. CLASS TestClass: DEF PRIVATE BUFFER MyTable_This FOR MyTable. DEF PUBLIC PROPERTY Value AS INT NO-UNDO GET: RETURN MyTable_This.Value. END. CONSTRUCTOR PUBLIC TestClass(i_rROWID AS ROWID): DO TRANSACTION: FIND FIRST MyTable_This WHERE ROWID(MyTable_This) = i_rROWID NO-LOCK. COMMIT. END. END. END.
注:NO-LOCK查询本身无需事务,但用独立事务包裹后,外部事务的UNDO操作不会影响该BUFFER的状态。
内容的提问来源于stack exchange,提问作者W0lfw00ds

