某某二院项目检查数据库Data增长过快,发现增加最快的为^CacheStream
,此流中存的数据前面300条为websys.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记录,表中对应的是最后三条流记录。
下图是运行三次后的截图:
- ^CF.websys.AddInsTmplS没有增加数据,^CF.websys.AddInsTmplD关联的是^CacheStream
如果此方法是业务应用方法,就会产生大量无效流数据,且流数据一般是内容非常长的数据,占用空间大。
使用##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
值
每次修改流内容只是修改了^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
无论持久化与否,都只在进程中有效访问量: 509665