假设有一个类 "X.Y.Z"
它的SQL表名称是什么?如何通过ObjectScript获取??
快速的搜素不能显示任何方法或属性。文档有点 "不对" 说 SQL 表名称是一样的. 至少应该是 'x_y.z'.
答案见英文社区:https://community.intersystems.com/post/getting-sql-table-name-given-cl…
假设有一个类 "X.Y.Z"
它的SQL表名称是什么?如何通过ObjectScript获取??
快速的搜素不能显示任何方法或属性。文档有点 "不对" 说 SQL 表名称是一样的. 至少应该是 'x_y.z'.
答案见英文社区:https://community.intersystems.com/post/getting-sql-table-name-given-cl…
在Ensemble中使用SQL进行批量插入
你好,社区。
我试图在一个表中插入多个值。下面是简单的SQL语句。
插入到表X中
values ('Name', 'Address', 'Phone')
我怎样才能在一条语句中进行多次插入(行)?
数值不在另一个表中,所以我不能使用选择进入。
谢谢。
吉米-克里斯蒂安
Hello Community,
I am trying to insert multiple values in a table. Below is the simple sql statement.
Insert Into TableX
values ('Name', 'Address', 'Phone')
How can i do multiple inserts(rows) in one single statement?
Values are not in another table, so i cannot use Select into.
Thanks,
Jimmy Christian.
我想知道是否有更好的方法来使用动态SQL对数据集进行分页,而不是我下面使用的方法。问题是,当潜在的数据池变大时,这段代码就会变慢,以至于无法使用。在分析下面的每一行代码时,似乎速度变慢与最初的rset.%Next()迭代有关。 有没有什么不需要子查询/%VID的可用方法,比如简单的LIMIT/OFFSET?
我的代码类似于:
s sql=##class(%SQL.Statement).%New()
s query="SELECT *,%VID FROM (SELECT prop FROM table WHERE prop=x) WHERE %VID BETWEEN 1 AND 100"
s sc=sql.%Prepare(query)
s rset=sql.%Execute()
while rset.%Next() {.....
Hi, 请问如何更改表(有数据)上的主键?谢谢!
答:
如果数据已经存在,那么这是一项必须重视的任务,特别是如果存在继承或父/子关系,因为这将导致你的数据存储方案的改变。
最简单的方法是通过一个中间(临时)表来实现。
创建一个具有相同结构的新类,但有一个新的主键。
使用SQL(不是合并命令)将数据从旧的类中移到它里面。
删除旧类中的数据/索引,然后改变其中的主键。
使用合并命令,将数据从新类移到旧类中。
删除带有数据的新类。
重建索引(如果有的话)。
几个有用的链接:
MERGE
如果仍然有问题,最好向WRC寻求帮助。
可以通过以下方式定义表:
MyApp.Person表可以使用DDL CREATE TABLE语句来定义,指定SQL schema.table名称。成功执行这个SQL语句会生成一个相应的持久化类,包名MyApp,类名Person。当使用DDL命令定义一个表时,你不需要指定USEEXTENTSET或创建一个位图范围索引。InterSystems SQL会自动应用这些设置,并将它们包含在预测的持久化类中。默认情况下,CREATE TABLE在相应的类定义中指定了Final类的关键字,表示它不能有子类。
CREATE TABLE MyApp.Person (
Name VARCHAR(50) NOT NULL,
SSN VARCHAR(15) DEFAULT 'Unknown',
DateOfBirth DATE,
Sex VARCHAR(1)
)ClassMethod CreateTable() As %String
{
&sql(CREATE TABLE Sample.Employee (
EMPNUM INT NOT NULL,
NAMELAST CHAR (30) NOT NULL,
NAMEFIRST CHAR (30) NOT NULL,
STARTDATE TIMESTAMP,
SALARY MONEY,
ACCRUEDVACATION INT,
ACCRUEDSICKLEAVE INT,
CONSTRAINT EMPLOYEEPK PRIMARY KEY (EMPNUM)))
IF SQLCODE=0{ WRITE "Table created" RETURN "Success"}
ELSEIF SQLCODE=-201 { WRITE "Table already exists" RETURN SQLCODE}
ELSE { WRITE "Serious SQL Error, returing SQLCODE " RETURN SQLCODE_" "_%msg}
}本文概述了InterSystems SQL的特点,特别是那些没有被SQL标准所涵盖或与InterSystems IRIS 数据平台的统一数据架构有关的特点。假定你已有SQL的知识,本文不是SQL概念或语法的介绍。
在InterSystems SQL中,数据是在表内呈现的。每个表都被定义为包含若干列。一个表可以包含零个或多个数据值的行。以下术语大致上是等同的。
| 数据 | 关系型数据库术语 | InterSystems SQL术语 | InterSystems IRIS术语 |
|---|---|---|---|
| database | schema | schema | package |
| database | table | table | persistent class |
| field | column | column | property |
| record | row | row |
SQL schema提供了一种将相关表、视图、存储过程和缓存查询分组的方法。模式的使用有助于防止在表一级的命名冲突,因为一个表、视图或存储过程的名称必须只在其schema内是唯一的。一个应用程序可以在多个schema中指定表。
SQL schema对应于IRIS中持久化的类包。
InterSystems SQL为存储在IRIS数据库中的数据提供不折不扣的、标准的关系型访问。
InterSystems SQL具有以下优点。
高性能和可扩展性 - InterSystems SQL的性能和可扩展性优于其他关系型数据库产品。
与IRIS对象技术的集成 - InterSystems SQL与IRIS对象技术紧密集成。你可以混合使用关系型和对象型的数据访问,而不牺牲任何一种方法的性能。
低维护 - 与其他关系型数据库不同,IRIS应用程序不需要在部署的应用程序中重建索引和压缩表。
支持标准SQL查询 - InterSystems SQL支持SQL-92标准语法和命令。
你可以将InterSystems SQL用于许多目的,包括。
基于对象和Web应用程序 - 你可以在InterSystems Object和Caché Server Page应用程序中使用SQL查询,以执行强大的数据库操作,如查询和搜索。
在线事务处理 - InterSystems SQL为插入和更新操作以及通常在事务处理应用程序中发现的查询类型提供出色的性能。
BI和数据仓库 - IRIS多维数据库引擎和位图索引技术的结合使其成为数据仓库式应用的绝佳选择。
点对点查询和报告 - 你可以使用InterSystems SQL包含的全功能ODBC和JDBC驱动来连接到流行的报告和查询工具。
嵌入式 Python 允许使用 Python 作为编程 IRIS 应用程序的本机选项。
使用嵌入式 所需的 版本取决于运行的平台。
在 Microsoft Windows 上, 安装工具包安装正确版本的 Python(当前为 ),仅用于嵌入式 。如果在开发机器上并希望将 用于一般用途,建议从 下载并安装相同的版本。
许多基于 UNIX 的操作系统都安装了 。如果需要安装,请使用包管理器为操作系统推荐的版本,例如:
macOS:使用 Homebrew 安装 Python 3.9 如果收到“无法加载 ”的错误,这意味着没有安装 Python,或者系统上安装了意外版本的 。使用上述方法之一安装或重新安装。
在基于 的系统上,可能希望使用 命令安装 包。如果尚未安装 ,请使用系统的包管理器安装包 。
要防止在运行 时出现 错误,请启用 。在管理门户中,,选择 ,然后选中启用服务框。
本节详细介绍了运行 的几种方法:
可以从终端会话或命令行启动 。
通过调用 类的 方法,从 终端会话启动 。这将以交互模式启动 解释器。终端会话中的用户和命名空间被传递给 。
通过键入命令 退出 。
嵌入式 Python 允许将 Python 与 IRIS 数据平台的本地编程语言 ObjectScript 一起使用。当使用嵌入式 在 类中编写方法时, 源代码与编译后的 代码一起编译为在服务器上运行的目标代码。与使用网关或 的 相比,这允许更紧密的集成。还可以导入 包,无论它们是自定义的还是公开的,并在 代码中使用它们。 对象是 中的一等公民,反之亦然。
ObjectScript 的 Python 库 - 此方案假设 开发人员,并且希望利用 开发人员社区可用的众多 库的强大功能。ObjectScript 和 开发人员组成的混合团队中,并且想知道如何一起使用这两种语言。将需要 或更高版本的正在运行的 实例,以及取决于操作系统的一些先决条件。还需要知道如何访问终端,即 IRIS 命令行工具。
本文档中的一些示例使用来自 上 存储库的类:https://github.com/intersystems/Samples-Data。 建议创建一个名为 的专用命名空间并将样本加载到该命名空间中。如果想查看或修改示例代码,则需要设置集成开发环境 ()。推荐使用 。
除了推荐的 REST 应用程序支持之外,产品还支持两种类型的传统 Web 应用程序:CSP 和 。在配置使用 和 的自定义登录页面时,遵循推荐的协议很重要。这些协议提供了更高的安全性,并最大限度地减少了升级到新产品或版本时的不兼容性。
创建自定义 登录页面:
%CSP.Login 页面的子类。Draw 方法,以便页面看起来像想要的那样。其中包括修改登录页面外观的方法和修改安全令牌页面外观的方法(如果使用双因素身份验证):DrawHEAD、DrawSTYLE、请注意, 和 DrawSTTitle 方法调用 DrawTitleSection 方法。
重要提示:创建自定义登录页面时,必须使用 的子类。在 应用程序中创建登录页面的其他方法可能会导致各种问题。 如果编写了不使用 子类的自定义登录页面,并且应用了来自任何用于升级或保护实例的更改,那么登录页面可能会失败而没有错误消息。例如,用户可能会尝试使用有效的用户名和密码登录,但他们的登录将在没有任何明显原因的情况下失败。这种情况可能表明需要更改自定义登录以使用所需的方法。
第二十一章 使用工作队列管理器(四)
分离和附加工作队列
通常,初始化一组工作程序,将工作项排队,然后等待工作程序完成工作项。但是,可能会遇到工作人员作业完成工作项所需的时间比预期更长的情况,或者无法将单个进程专门用于等待。因此,工作队列管理器使能够将工作队列与进程分离,然后将工作队列附加到同一进程或不同的进程。
例如,假设队列引用了初始化的工作队列。还假设向工作队列中添加了几个工作项。在调用 Wait() 或 WaitForComplete() 来确定正在处理的工作的状态之前,可以使用以下方法:
Detach()
method Detach(ByRef token As %String, timeout As %Integer=86400) as Status 从初始化工作队列时创建的对象引用中分离工作队列对象。 Detach() 方法使任何正在进行的工作能够继续并保留工作队列的当前状态。
token 参数表示一个安全令牌,可以使用它随后将工作队列附加到另一个进程。 timeout 参数是可选的,它指示系统保留分离的工作队列对象的时间量(以秒为单位)。超时期限过后,系统会删除与工作队列关联的所有工作人员作业和信息。超时的默认值为 1 天。
调用 Detach() 方法后,对分离对象引用的大多数调用都会返回错误。
一个类别是一个独立的worker jobs池。当初始化一组worker jobs时,可以指定提供worker的类别。如果集合中的任何worker jobs在执行work项时请求额外的worker jobs,则新的worker jobs来自同一类别。
例如,假设系统提供的 SQL 类别分配了最多 8 个worker。然后,假设与BusinessIntelligence相关的流程创建了一个类别,并将最多四个worker分配给该类别。如果 SQL 池中的所有worker在给定时间都参与了工作,则 BusinessIntelligence 类别中的worker可能仍然可以立即处理工作项。
系统包括两个不能删除的类别: 和 。 SQL 类别适用于系统执行的任何 SQL 处理,包括查询的并行处理。当在未指定类别的情况下初始化一组worker jobs时,默认类别提worker jobs。
每个类别都具有影响该类别中每个工作队列的行为的属性。这些属性是:
当创建此类别中的工作队列且未指定worker job 计数时,这将成为工作队列中worker job 的数量。此属性的默认值是核心数。
在此类别的job服务请求池中保留的活动worker job的最大数量。
可以通过执行以下步骤来使用工作队列管理器:
ObjectScript 代码划分为工作单元,这些工作单元是满足特定要求的类方法或子例程。%SYSTEM.WorkMgr 类的一个实例。为此,请调用 %SYSTEM.WorkMgr 类的 %New() 方法。该方法返回一个工作队列。可以指定要使用的并行worker jobs的数量,也可以使用默认值,这取决于机器和操作系统。此外,如果已创建类别,则可以指定应从中获取job的类别。
创建工作队列时,工作队列管理器会创建以下工件:
Queue() 或 QueueCallback() 方法。作为参数,传递类方法(或子例程)的名称和任何相应的参数。对添加到队列的项目立即开始处理。
如果队列中的项目多于队列可用的worker jobs,则job会竞争清空队列。例如,如果有 100 个项目和四个job,则每个job从队列的头部移除一个项目,处理它,然后返回到队列的头部以移除并处理另一个项目。这种模式一直持续到队列为空。
工作队列管理器是的一项功能,使能够通过以编程方式将工作分配给多个并发进程来提高性能。在引入工作队列管理器之前,可能已经使用 JOB 命令在应用程序中启动多个进程并使用自定义代码管理这些进程(以及任何导致的故障)。工作队列管理器提供了一个高效且直接的 API,使能够卸载流程管理。
代码在多个地方内部使用工作队列管理器。可以将它用于自己的需求,如以下部分中的高级描述。
计算机硬件开发的最新创新趋向于高性能、多处理器或多核架构。与此同时,内存和网络设备的速度也只是慢慢地提高了。 开发了工作队列管理器以响应这些趋势并根据以下原则:
尽管整个数据平台旨在尽可能高效地利用系统中的硬件资源,但该平台的工作队列管理器功能专门设计用于利用现代硬件配置中可用的额外 CPU 资源。工作队列管理器有两个关键用途:
进程使用许多不同的资源来实现其目标。其中包括部分或全部 CPU 周期、内存、外部存储、网络带宽等。这篇文章是关于内存使用的。具体来说,它处理为数据存储分配的内存,例如:
当第一次为它们分配值时,它们被分配了内存空间。在局部数组的情况下,局部变量名称加上所有下标的值的组合引用单个变量值。
除了包含极长字符串的变量外,变量会占用与 $STORAGE 相关的空间。包含极长字符串的变量以不同方式存储,并且不占用 $STORAGE 中的空间。
每当实例化一个对象时,都会分配空间来保存对象的当前内容以及它所引用的对象。删除最后一个对象引用时返回该空间。
I/O 缓冲区将与该进程正在使用的设备相关联的 I/O 缓冲区存储在进程空间中。
进程从用于上述实体的初始内存池开始。当应用程序创建它们时,它们会消耗池中的内存;当应用程序删除它们时,它们的内存将返回到池中。例如,当一个例程开始执行时,总是会创建消耗一些内存的局部变量;当例程返回并且这些变量超出范围时,这些变量使用的内存将被返回并可供重用。
当应用程序需要内存,并且进程在其内存池中没有足够大(连续)的可用内存区域来满足需求时,该进程会从底层操作系统请求额外的内存块以添加到其池中。稍后,如果该内存块完全未使用,它将返回给操作系统。
XML 消息文件是消息字典的导出。这也是希望导入的任何消息的必需格式。
只要有可能,XML 消息文件应该使用 UTF-8 编码。但是,在某些情况下,开发人员或翻译人员可能会使用本地平台编码,例如 shift-jis,以便于编辑 XML 消息文件。无论 文件使用何种编码,应用程序的语言环境都必须支持它,并且它必须能够表达该语言的消息。
消息文件可能包含一种语言和多个域的消息。
元素是 XML 消息文件的顶级容器,每个文件只有一个 元素。
元素有一个必需的属性,Language。 属性的值是一个全小写的 代码,用于标识文件的语言。它由一个或多个部分组成:主要语言标签(例如 或 )可选地后跟连字符 () 和次要语言标签( 或 )。
在以下示例中,此语言为(英语)。
<?xml version="1.0" encoding="utf-8" ?>
<MsgFile Language="en">
<MsgDomain Domain="sample">
<Message Id="source">Source</Message>
<Message Id="menu">Samples Menu</Message>
</MsgDomain>
</MsgFile>
Hi 社区,
在这篇文章中,我将解释如何通过使用嵌入式python访问管理门户系统的仪表盘信息和表数据。.png)
本文概述了字符串本地化,并描述了如何导出、导入和管理消息字典。
当本地化应用程序的文本时,会创建一种语言的文本字符串清单,然后当应用程序区域设置不同时,建立约定以另一种语言替换这些消息的翻译版本。
支持以下本地化字符串的过程:
REST 应用程序或商业智能模型中)。这种机制各不相同,但最常见的机制是 $$$Text 宏。代替硬编码的文字字符串,开发人员包含 $$$Text 宏的实例,为宏参数提供如下值:
write "Hello world"
替换为
write $$$TEXT("Hello world","sampledomain","en-us")
$$$Text 宏的每个唯一实例生成条目。消息字典是全局的,因此可以在管理门户中轻松查看(例如)。有一些类方法可以帮助完成常见任务。
结果是一个或多个 XML 消息文件,其中包含原始语言的文本字符串。
发布工程师将这些文件发送给翻译人员,请求翻译版本。
翻译人员使用他们喜欢的任何 XML 创作工具来处理 XML 消息文件。
可根据此思想进行多任务启动查询汇总数据。
job机制开启后台进程。loop循环减少进程的数量等于开启进程的数量,判断多进程任务是否完成。创建表并插入1000W条数据,统计Moeny字段总金额
创建demo代码如下。
Class Demo.SemaphoreDemo Extends %RegisteredObject
{
/// Do ##class(Demo.SemaphoreDemo).Sample(5)
ClassMethod Sample(pJobCount = 3)
{
k ^yx("Amt"),^yxAmt
/* 1.启动信号 */
s mSem = ##class(Demo.Sem).%New()
If ('($isobject(mSem)))
{
q "启动失败"
}
/* 2. 初始化信号量为0 */
d mSem.Init(0)
s t1 = $zh
/* 3. 按指定数量,启动后台任务 */
for i = 1 : 1 : pJobCount
{
j ..Task(i)
}
w "启动job时间:"_ ($zh - t1),!
/* 4. 等待后台任务完成 */
s tCount = i,tSC = 0
/* 后台任务完成的判断条件是:减少的信号量=总后台任务数 */
while (tSC < tCount)
{
s tSC = tSC + mSem.Decrement(tCount, 10)
}
w "完成时间:"_ ($zh - t1),!
s moneyAmt = 0
s data = ""
for {
s data = $o(^yxAmt(data))
q:(data = "")
s moneyAmt = moneyAmt + ^yxAmt(data)
}
d mSem.Delete()
w "总金额" _ moneyAmt,!
w "汇总时间:"_ ($zh - t1),!
q
}
ClassMethod Task(i)
{
s tSem = ##class(Demo.Sem).%New()
s moneyAmt = 0
for j = (i * 100000) + 1 : 1 : (i + 1) * 100000 {
s money = $li(^M.YxPersonD(j), 3)
s moneyAmt = moneyAmt + money
}
s ^yxAmt("moneyAmt" _ i) = moneyAmt
s ^yx("Amt") = $i(^yx("Amt"))
d tSem.Open(##class(Demo.Sem).Name())
d tSem.Increment(1)
d tSem.%Close()
q moneyAmt
}
}
Main、Producer 和 Consumer 这三个类中的每一个都有自己的 方法,最好在各自的终端窗口中运行它们。每次运行时,它都会显示它为日志生成的消息。一旦用户通过提供它正在等待的输入来响应 类, 的 方法将终止删除信号量。然后,用户可以通过键入命令查看所有进程的合并日志文件的显示
Do ##class(Semaphore.Util).ShowLog()
注意:以下所有示例都假定所有类都已在命名空间中编译。
最简单的例子演示了信号量的创建和销毁。它使用 类。请执行下列操作:
Do ##class(Semaphore.Main).Run()
Enter 键。该方法显示信号量的初始化值,将其删除,然后退出。按照上述步骤在终端窗口中显示的消息示例如下
这个例子展示了生产者在工作,以及从两个进程中捕获日志消息。
“A”和“B”。A 中,键入以下命令,但不要在末尾键入 ENTER 键 -Do ##class(Semaphore.Main).Run()
下面是一系列使用信号量实现生产者/消费者场景的类。 “主”进程初始化信号量并等待用户指示活动已全部完成。生产者在循环中随机增加一个信号量值,更新之间的延迟可变。消费者尝试在随机时间从信号量中删除随机数量,也是在循环中。该示例由 5 个类组成:
Main – 初始化环境并等待信号量上的活动完成的类。Counter – 实现信号量本身的类。它记录它的创建以及由于信号量在等待列表中而发生的任何回调。Producer – 一个类,其主要方法增加信号量值。增量是一个随机选择的小整数。完成增量后,该方法会在下一个增量之前延迟一小段随机数秒。Consumer 消费者——这是对生产者的补充。此类的主要方法尝试将信号量减少一个随机选择的小整数。它将递减请求添加到其等待列表中,等待时间也是随机选择的秒数。注意:组成这些类的代码特意写得简单。尽可能地,每个语句只完成一个动作。这应该使用户更容易和更直接地修改示例。
此类建立演示环境。它调用实用程序类来初始化日志和名称索引工具。
维基百科对信号量有这样的定义:“在计算机科学中,特别是在操作系统中,信号量是一种变量或抽象数据类型,用于控制多个进程在并行编程或多用户环境中对公共资源的访问。”信号量不同于互斥体(或锁)。互斥锁最常用于管理竞争进程对单个资源的访问。当一个资源有多个相同的副本并且这些副本中的每一个都可以由单独的进程同时使用时,就会使用信号量。
考虑一个办公用品商店。它可能有几台复印机供其客户使用,但每台复印机一次只能由一个客户使用。为了控制这一点,有一组键可以启用机器并记录使用情况。当客户想要复印文件时,他们向职员索取钥匙,使用机器,然后归还钥匙,并支付使用费。如果所有机器都在使用,客户必须等到钥匙归还。保存键的位置用作信号量。
该示例可以进一步推广到包括不同类型的复印机,也许可以通过它们可以制作的副本的大小来区分。在这种情况下,将有多个信号量,如果复制者在复制的大小上有任何重叠,那么希望复制共同大小的客户将有两个资源可供提取。
信号量是共享对象,用于在进程之间提供快速、高效的通信。每个信号量都是类 %SYSTEM.Semaphore 的一个实例。信号量可以建模为一个共享变量,它包含一个 64 位非负整数。信号量上的操作在共享它的所有进程中以同步的方式更改变量的值。按照惯例,值的变化会在共享信号量的进程之间传递信息。
注:IRIS有,Cache无。
^LOGDMN 例程允许管理结构化日志记录;还有一个基于类的 API,将在下一节中介绍。
要使用 ^LOGDMN 启用结构化日志记录:
set $namespace="%sys"
do ^LOGDMN
这将启动一个带有以下提示的例程:
1) Enable logging
2) Disable logging
3) Display configuration
4) Edit configuration
5) Set default configuration
6) Display logging status
7) Start logging
8) Stop logging
9) Restart logging
LOGDMN option?
4 以便可以指定配置详细信息。然后,该例程会提示输入以下项目:a. 最低日志级别,以下之一:
-2 — 详细的调试消息(例如十六进制转储)。-1 — 不太详细的调试消息。1(默认值)— 警告,表示可能需要注意但未中断操作的问题。2 — 严重错误,表明问题已中断操作。b. 管道命令,它指定系统将结构化日志发送到哪里。
IRIS 支持结构化日志记录。
创建多个日志,每个日志用于不同的目的。从以前的产品迁移过来的客户可以像过去一样利用这些日志,但现在还可以将所有日志信息导入一个单一的、中央的、机器可读的日志文件——结构化日志。然后可以将此文件与第三方分析工具一起使用。
本文概述了结构化日志中的信息,展示了日志示例,并描述了如何启用结构化日志记录。
当启用结构化日志记录时,系统会将相同的数据写入结构化日志,它也会写入其他日志(无论哪个)。例如,系统将相同的行写入messages.log 和结构化日志。
启用结构化日志记录后,结构化日志包含以下所有信息:
messages.log 的信息。这包括需要注意的警报、有关系统启动和关闭的信息、有关日志文件和 WIJ 文件的高级信息、有关配置更改 (CPF) 的信息以及与许可相关的信息。本部分显示结构化日志记录实用程序的示例输出,用于名称/值对格式和 JSON 格式。
以下输出使用格式选项 (名称/值对)。此示例经过编辑以用于显示目的;在实际输出中,每个条目只占一行,条目之间没有空行。
when="2019-08-01 18:43:02.216" pid=8240 level=SEVERE event=Utility.Event
text="Previous system shutdown was abnormal, system forced down or crashed"
when="2019-08-01 18:43:05.290" pid=8240 level=SEVERE event=Utility.Event
text="LMF Error: No valid license key. Local key file not found and LicenseID not defined."
when="2019-08-01 18:43:05.493" pid=8240 level=WARNING event=Generic.Event
text="Warning: Alternate and primary journal directories are the same"
when="2019-08-01 18:46:10.493" pid=11948 level=WARNING event=System.Monitor
text="CPUusage Warning: CPUusage = 79 ( Warnvalue is 75)."
要创建一个存储为整数的新位串,请对每个位求和 2 的幂:
set bitint = (2**2) + (2**5) + (2**10)
write bitint
1060
要将现有位串中的位设置为 1,请使用 $zboolean 函数(逻辑 OR)的选项7 :
set bitint = $zboolean(bitint, 2**4, 7)
write bitint
1076
要将现有位串中的位设置为 ,请使用 函数的选项 :
set bitint = $zboolean(bitint, 2**4, 2)
write bitint
1060
要在现有位串中切换位,请使用 函数(逻辑 )的选项 :
要将位字符串显示为整数,可以使用如下方法,该方法循环位并使用 函数:
此方法使用函数将位字符串中的哪些位设置为整数,该函数返回以10为底的对数值。该方法删除越来越小的位串块,直到没有剩余:
使用 函数对存储为整数的位串执行按位逻辑运算。
对于此示例,假设有两个位串 和 ,存储为整数,以及一个 方法,如 中定义的,用于显示这些位。
使用 函数的选项 对位执行逻辑 :
使用 函数的选项 对位执行逻辑与:
要创建新的位串,请使用 $bit 函数将所需位设置为 1:
kill bitstring
set $bit(bitstring, 3) = 1
set $bit(bitstring, 6) = 1
set $bit(bitstring, 11) = 1
使用 将现有位串中的位设置为 1:
set $bit(bitstring, 5) = 1
使用 将现有位串中的位设置为 0:
set $bit(bitstring, 5) = 0
由于位串中的第一位是位 ,因此尝试设置位 会返回错误:
要测试是否在现有位串中设置了位,还可以使用 函数:
如果测试未明确设置的位,则 $bit 返回 0:
要显示位串中的位,请使用 $bitcount 函数获取位串中位的计数,然后遍历位:
还可以使用 来计算位串中 或 的数量:
要查找在位串中设置了哪些位,请使用 函数,该函数返回指定值的下一位的位置,从位串中的给定位置开始:
此方法搜索字符串并在 返回 时退出,表示没有找到更多匹配项。
在测试位串的比较时要非常小心。
例如,可以有两个位串 和 ,它们具有相同的位集:
然而,如果你比较它们,你会发现它们实际上并不相等:
如果你使用 ,你可以看到这两个比特环的内部表示是不同的:
在这种情况下, 将第 位设置为 :
如果要将一系列布尔参数传递给方法,一种常见的方法是将它们作为编码为单个整数的位序列传递。
例如,Security.System.ExportAll() 方法用于从 IRIS 实例中导出安全设置。如果查看此方法的类引用,将看到它的定义如下:
classmethod ExportAll(FileName As %String = "SecurityExport.xml",
ByRef NumExported As %String, Flags As %Integer = -1) as %Status
第三个参数 Flags 是一个整数,其中每个位代表一种可以导出的安全记录。
有时可能希望在基于数据平台的应用程序中存储一系列相关的布尔值。可以创建许多布尔变量,也可以将它们存储在数组或列表中。或者可以使用称为“位串”的概念,它可以定义为位序列,首先呈现最低有效位。位串允许您以非常有效的方式存储此类数据,无论是在存储空间还是处理速度方面。
位串可以以两种方式之一存储,作为压缩字符串或整数。如果在没有上下文的情况下听到术语“位串”,则表示位序列存储为压缩字符串。本文向介绍了这两种类型的位串,然后介绍了一些可用于操作它们的技术。
存储位序列的最常见方式是在位串中,这是一种特殊的压缩字符串。除了节省存储空间外,还可以使用 ObjectScript 系统函数有效地操作位串。
这样的系统函数是 $factor,它将整数转换为位串。我们可以通过执行以下语句将整数 11744 转换为位串:
set bitstring = $factor(11744)
要查看位串内容的表示,可以使用 命令:
zwrite bitstring
bitstring=$zwc(128,4)_$c(224,45,0,0)/*$bit(6..9,11,12,14)*/
起初它看起来很神秘,但在输出的末尾,会看到一条注释,其中显示了已设置的实际位的列表:6、7、、、、 和 。位串中的位 表示 ,位 表示 ,依此类推。将所有位加在一起,我们得到 。
增量锁定具有潜在危险,因为它可能导致称为死锁的情况。当两个进程各自对已被另一个进程锁定的变量断言增量锁定时,就会出现这种情况。因为尝试的锁是增量的,所以现有的锁不会被释放。结果,每个进程在等待另一个进程释放现有锁的同时挂起。
举个例子:
A 发出此命令:lock + ^MyGlobal(15)B 发出此命令:A 发出此命令:此 LOCK 命令不返回;进程被阻塞,直到进程 释放这个锁。
B 发出此命令:lock + ^MyGlobal(15)此 LOCK 命令不返回;进程被阻塞,直到进程 释放这个锁。但是,进程 A 被阻塞,无法释放锁。现在这些进程都在等待对方。
有几种方法可以防止死锁:
timeout 参数。如果发生死锁,可以使用管理门户或
本节介绍在实践中使用锁的基本方法。
使用升级锁来管理大量锁。当锁定数组的节点时,它们是相关的,特别是当将多个节点锁定在同一下标级别时。
当给定进程在同一数组中的给定下标级别创建了超过特定数量(默认为 1000)的升级锁时, 将删除所有单独的锁名称并用新锁替换它们。新锁位于父级,这意味着数组的整个分支被隐式锁定。示例(如下所示)演示了这一点。
应用程序应在合适的情况下尽快释放特定子节点的锁(与非升级锁完全相同)。当释放锁时, 会减少相应的锁计数。当的应用程序移除足够多的锁时,会移除父节点上的锁。第二小节显示了一个示例。
假设有 1000 个^MyGlobal("sales","EU",salesdate) 形式的锁,其中 salesdate 表示日期。锁表可能如下所示:
注意 Owner 19776 的条目(这是拥有锁的进程)。 ModeCount 列指示这些是共享的、升级的锁。
当同一进程试图创建另一个相同形式的锁时, 会升级它们。它会移除这些锁并用名称为 ^MyGlobal("sales","EU") 的单个锁替换它们。现在锁表可能如下所示:
列表明这是一个共享的升级锁,它的计数是 1001。
请注意以下关键点:
^MyGlobal("sales","EU") 的所有子节点现在都被隐式锁定,遵循数组锁定的基本规则。