使用信息表
信息表作为缓存中的单个对象存储在内存中。因此,ThingWorx 8.5 及更高版本不支持直接对信息表进行操作,因为这样可能会导致意外行为和性能问题。从事物中检索信息表属性时会创建一个代理对象,该对象可同原始对象进行通信。直接更改仅适用于本地副本,但函数调用将更新原始对象。如果需要完整的对象副本,以便在更新所有数据前不会对任何更改进行代理,请使用资源的复制选项。在下面的示例中,对于单行信息表,我们使用一个包装对象,但对于多行信息表,我们使用完整的复制选项,因为我们不希望更新每行更改。
下面创建了一个本地代理对象 (方法调用将更新原始对象并将其保存至缓存):
Things["data1"] 按名称搜索 "data1" 事物。
Things["data1"].info - "data1" 事物的 "info" 信息表属性
var myinfo = Things["data1"].info
下面创建了一个未将任何更改代理回原始对象的完整副本:
var myinfo = Resources["InfoTableFunctions"].Clone({ t1: Things["data1"].info });
ThingWorx 8.5 及更高版本中属性数据的处理方式与先前版本中有所不同。所有数据现在都存储在缓存层中,以便可在高可用性群集环境中本地或远程使用。在先前的环境中,所存储的数据可直接进行修改,但在缓存层中,数据在进行更改时必须在缓存中移入或移出。在群集环境中,缓存是分布式的;因此,额外网络延迟和线序列化会使所做的每个请求的时间增加。
现在。将大量数据以信息表形式存储在一个属性中成本十分高昂,且可能会导致系统在群集环境中崩溃。现在,信息表发生更改时会完全读取和写入属性。在群集环境中,也将对整个对象进行序列化、反序列化并发送至整个线路。您应该将大型信息表移动到数据库中,而不是将其存储在单个属性中。可将其转换为用户定义的表或放置在数据表中。
在群集环境中,使用的是 Apache Ignite。推送大型对象可能会导致 Ignite 不响应。Ignite 将排队执行写入和备份,当推送较大值时,可能需要时间进行处理且可能会导致处理备份。如果备份变得很大,Ignite 系统线程将开始阻塞,这可能导致 Ignite 认为某一节点未响应而将其关闭。可能会有越来越多的数据过期。
要在群集环境中正常工作,可能需要更改应用程序,以减小存储在属性中的数据的大小。通常,包含数千行的信息表可能导致次问题。
示例:排序信息表
本示例以往发生在添加缓存层之前,用于直接更新内存中的表格。
var sort = new Object();
sort.name = yourFieldName;
sort.ascending = booleanValue;
me.yourInfoTable.Sort(sort);
但现在应按如下方式执行:
创建一个本地信息表并予以更改,然后将其分配回事物信息表属性。
此时将从缓存中提取对象并进行复制。然后,您可在不影响原始属性的情况下更改此副本,直至完成设置。
如果情况并非如此,则每次接触信息表都会导致整个对象被写回缓存,进而导致性能下降。
var localInfoTable = me.yourInfoTable;
var sort = new Object();
sort.name = yourFieldName;
sort.ascending = booleanValue;
localInfoTable.Sort(sort);
me.yourInfoTable = localInfoTable;
示例:更新单行信息表的字段值
错误方法:
此脚本中的每一行都将从缓存中获取整个信息表并更改某个值,然后将其放回到缓存中。到缓存的往返会花费一些时间,因为它每次都会处理整个信息表。这将对远程系统中的缓存执行六次调用,且会降低脚本的运行速度。
Things["data1"].info.v1 = 1;
Things["data1"].info.v2 = 2;
Things["data1"].info.v3 = 3;
正确方法:
此示例将从缓存中获取信息表副本并于本地更新所有数据,然后将信息表放回到缓存中。这样可将缓存的调用次数减少到两次。
var myinfo = Things["data1"].info
myinfo.v1 = 1
myinfo.v2 = 2
myinfo.v3 = 3
Things["data1"].info = myinfo
示例:更新所有单行信息表的字段值
以下示例演示了通过将信息表分配给本地变量,来创建一个信息表副本。对原始对象所做的更改不会体现在复制值中。
// creates a clone of InfoTable
var myinfo = Things["data1"].info;
// sets value of v1 to 5 in local InfoTable
myinfo.v1 = 5;
// change the orignal data1's v1 field value to 4, will not update the local value, it is still 5
Things["data1"].info.v1 = 4;
// assigning local info table to data2 so its v1 will have a value of 5
Things["data2"].info = myinfo;
示例:多行信息表的行为更改
从以下示例中可以看出信息表的复本仍为代理对象。针对代理对象调用的方法同样适用于主对象。以下内容与代理一致,但不同于 ThingWorx 8.4 行为。在 ThingWorx 8.4 中,如果使 me.p2 = prop2,则会断开对原始对象的引用。但在 ThingWorx 9 中却并非如此,因为它们被视为相同的对象代理。
// An InfoTable local object for the "v1" field
var newEntry = new Object();
newEntry.v1 = 1;
// creates a proxy object from local object prop1 -> me.p1
var prop1 = me.p1;
prop1.v1=4;
// creates a proxy object from local object prop2 -> me.p2
var prop2 = me.p2;
prop2.v1=5;
// updates the me.p1 object, this breaks the proxy between prop1 -> me.p1
me.p1=prop2;
// prop2 reference is unchanged, still proxied
me.p2=prop2;
// this will not change me.p1 since the reference was broken when the object assignement to prop2 was done
prop1.AddRow(newEntry);
// this will update me.p2, the object reference is the same
prop2.AddRow(newEntry);
示例:构建多行信息表
本示例将向信息表中添加多个行:
错误方法:
虽然下面的内容看似正确,因为其针对数据库使用了 AddRow 方法,但实际上它在每次循环迭代时都将更改代理到了原始对象。这将导致信息表在每次循环迭代时均被写入缓存,而这是我们不希望看到的。
var myinfo = Things["data1"].info;
for (i=0; i < 10; i++) {
var row = new Object();
row.v1 = i;
row.v2 = i * 2;
row.v3 = i * 3;
myinfo.AddRow(row);
}
Things["data1"].info = myinfo;
正确方法:
在本示例中,我们复制了对象,以便在将其分配回原始对象前,可在不产生任何影响的情况下对其进行处理。
var myinfo = Resources["InfoTableFunctions"].Clone({ t1: Things["data1"].info });
for (i=0; i < 10; i++) {
var row = new Object();
row.v1 = i;
row.v2 = i * 2;
row.v3 = i * 3;
myinfo.AddRow(row);
}
Things["data1"].info = myinfo;
以下示例同样可取。由于未使用代理对象方法,因此其在被分配前不会更改原始对象。
var myinfo = Things["data1"].info;
for (i=0; i < 10; i++) {
var row = new Object();
row.v1 = i;
row.v2 = i * 2* 10;
row.v3 = i * 3* 100;
myinfo.rows[i] = row;
}
Things["data1"].info = myinfo;
这对您有帮助吗?