HISUI
关于CacheStream流使用
2022年03月23日 12时44分

关于CacheStream流的使用

某某二院项目检查数据库Data增长过快,发现增加最快的为^CacheStream,此流中存的数据前面300条为websys.AddInsTmpl相关数据,后面为业务接口数据。如下图:
AddInsTmpl
但websys.AddInsTmpl表只有一条记录,正常来说只有一条流数据。

二、问题测试

当保存插件管理记录时,会重新生成Js流数据并存储,保存方法如下:

// 获得实体对象
ClassMethod GetCurrentObj()
{
    Set Id = $O(^CF.websys.AddInsTmplD(0))
    If (Id>0){
        Set Obj = ##class(websys.AddInsTmpl).%OpenId(Id)
    }else{
        Set Obj = ##class(websys.AddInsTmpl).%New()
    }
    Quit Obj
}
ClassMethod TestStream()
{
    // 打开实体对象
    Set Obj = ..GetCurrentObj()
    Set Obj.Code = $H
    // 赋字符流值对象
    Set Obj.InvokeJS = ##class(%GlobalCharacterStream).%New()
    Do Obj.InvokeJS.Write("<xml>第1次</xml>")
    Do Obj.%Save()
    Set Obj = ""
    Quit $$$OK
}

termainl运行此d ##class(xxx).TestStream()方法,每运行一次会增加三条CacheStream记录,表中对应的是最后三条流记录。
下图是运行三次后的截图:
cachestreamsql

  1. ^CF.websys.AddInsTmplS没有增加数据,^CF.websys.AddInsTmplD关联的是^CacheStream

  2. 如果此方法是业务应用方法,就会产生大量无效流数据,且流数据一般是内容非常长的数据,占用空间大。

三、修改办法

使用##class(%GlobalCharacterStream).%New()得到新流对象,把流内容复制给字段,再使用Clear()方法可以清空流内容,代码修改如下:

// 使用中间流对象
ClassMethod TestStream()
{
    // 打开实体对象
    Set Obj = ..GetCurrentObj()
    Set Obj.Code = $H
    Set Stream = ##class(%GlobalCharacterStream).%New()
    Do Stream.Write("<xml>第n次</xml>")
    If $IsObject(Obj.InvokeJS){ // 新增,修改都会走到这,初始化对象时流已被初始化
         Do Obj.InvokeJS.CopyFrom(Stream) // 覆盖表字段对应流内容 -此行代码非常重要-
         Do Stream.Clear()  // 清空内存流对象内容
    }
    Set Stream = ""
    Do Obj.%Save()
    Set Obj = ""
    Quit $$$OK
}

/// 不使用中间流对象 推荐
ClassMethod TestStream()
{
    // 打开实体对象
    Set Obj = ..GetCurrentObj()
    Set Obj.Code = $H
    Set Stream = Obj.InvokeJS
    Do Stream.Write("<xml>第n次</xml>")
    Set Stream = ""
    Do Obj.%Save()
    Set Obj = ""
    Quit $$$OK
}

/// 使用%Stream.GlobalCharacter 推荐
ClassMethod TestStream()
{
    // 打开实体对象
    Set Obj = ..GetCurrentObj()
    Set Obj.Code = $H
    Set Stream = ##class(%Stream.GlobalCharacter).%New()
    Do Stream.Write("<xml>第n次</xml>")
    Set Obj.InvokeJS = Stream
    Do Obj.%Save()
    Set Obj = ""
    Quit $$$OK
}

上面三种方式编写的类方法调用,就不会残留^CacheStream
cachestreamsqls
每次修改流内容只是修改了^CF.websys.AddInsTmplS的值,^CF.websys.AddInsTmplD也没有变化

%GlobalCharacterStream持久化时会存到^CacheStream中,否则在内存中。
%Stream.GlobalCharacter无论持久化与否,都只在进程中有效。且把流赋给对应关联Global(^CF.websys.AddInsTmplD记录关联的是^CacheStream就赋给^CacheStream,关联的是^^CF.websys.AddInsTmplS就赋给^CF.websys.AddInsTmplS)。

三、删除数据

删除表数据时,如果表对象的实体类有流字段,如果使用Kill方式一定要把关联的流Global删除

Kill ^CF.websys.AddInsTmplD(1)
Kill ^CF.websys.AddInsTmplS(2)   // 2为1记录关联的流对象id,不运行此句会残留流数据

使用对象或SQL语句删除方式可以同步删除流Global

Do ##class(websys.AddInsTmpl).%DeleteId(1)
// D与S的Global都会被删除
delete from websys.AddInsTmpl where id=2  -- D与S的Global都会被删除

四、总结

  • 使用%GlobalCharacterStream字符流时,过渡使用的字符流最后一定要Clear()掉,不然会永久存在^CacheStream中,占用空间

  • 如果是实体数据保存,可以直接使用字段流,不要再把%GlobalCharacterStream引用赋给字段,这会导致D-Global不关联S-Global,关联上^CacheStream,一直移除^CacheStream,导致数据丢失。

  • 如果使用%GlobalCharacterStream字符流时,不涉及保存数据,此流存在内存中,进程结束会自动清除

  • %Stream.GlobalCharacter无论持久化与否,都只在进程中有效
上一篇: 下一篇:

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注

访问量: 379528