搜索​​​​

清除过滤器
文章
姚 鑫 · 一月 18, 2023

第四十九章 使用 ^SystemPerformance 监视性能 - 复制配置文件

# 第四十九章 使用 ^SystemPerformance 监视性能 - 复制配置文件 # 复制配置文件 可以使用以下 `API` 命令将现有配置文件复制到具有不同名称的文件: ```java set rc=$$copyprofile^SystemPerformance("sourceprofilename","targetprofilename") ``` 必须指定: - `sourceprofilename` - 现有配置文件的名称 - `targetprofilename` - 要创建的配置文件的名称。这必须用双引号引起来。 如果成功,该函数返回 `1`。如果不成功,它返回一个 `0` 后跟一个 `carat` 和任何错误的原因。 其中 `sourceprofilename` 是现有配置文件的名称,`targetprofilename` 必须是唯一的并且不能包含空格或空白字符。 例如,要复制 `2minrun` 配置文件,请输入以下内容: ```java set rc=$$copyprofile^SystemPerformance("2minrun","5minrun") ``` 下次运行 `^SystemPerformance` 实用程序时,配置文件列表包括以下配置文件名称和说明: ```java 2minrun A 2-minute run sampling every 30 seconds 5minrun A 2-minute run sampling every 30 seconds ``` 现在可以按照本指南这一部分的编辑配置文件中的说明编辑新配置文件。 # 删除配置文件 可以使用以下 `API` 命令删除现有配置文件(预定义的“测试”配置文件除外): ```java set rc=$$delprofile^SystemPerformance("profilename") ``` - `profilename` - 要删除的配置文件的名称。这必须用双引号引起来。 如果成功,该函数返回 `1`。如果不成功,它返回一个 `0` 后跟一个 `carat` 和任何错误的原因。 例如,要删除 `2minrun` 配置文件,请输入以下内容: ```java set rc=$$delprofile^SystemPerformance("2minrun") ``` 下次运行 `^SystemPerformance` 实用程序时,配置文件列表不包括 `2minrun` 配置文件。 # ^SystemPerformance Utility 创建的性能报告 `^SystemPerformance` 实用程序生成特定于平台的报告,如本章所述。该报告分为几个部分,如下面的清单所示: ```java Configuration IRISTEST3 on machine testsystem Customer: InterSystems Development License : 123456 InterSystems IRIS Version String: InterSystems IRIS for Windows (x86-32) 2018.1 (Build 508) Fri Jan 26 2018 17:51:22 EDT -------------------------------------------------------------- Profile Profile run "test" started at 10:07 on Jun 01 2016. Run over 10 intervals of 30 seconds. -------------------------------------------------------------- license Product=Enterprise License Type=Concurrent User Server=Multi Platform=Heterogeneous Licensed Users=1000 Licensed CPUs=16 . . . -------------------------------------------------------------- End of InterSystems IRIS Performance Data Report ``` 本节中的表格描述了每个特定于平台的报告的部分。这些部分在每个表中按字母顺序列出,以帮助您更轻松地找到特定部分。仅收集一次的数据标有星号 (`*`)。其余数据是在整个配置文件运行过程中收集的。 注意:在以下所有表格中,标有 `*` 的数据每次运行收集一次。
文章
Jingwei Wang · 七月 25, 2022

ESB和注册中心概述

本章介绍了使用InterSystems IRIS作为企业服务总线,描述了InterSystems IRIS ESB架构,并提供了部署ESB的概述。 企业服务总线的概念 企业服务总线(ESB)提供了一个单点来访问和管理具有SOAP、REST或其他网络API的应用程序。ESB提供了以下功能。 提供一个中心来发现和访问服务。 将应用程序与服务隔离开来,允许你在一个地方改变服务的描述,而不需要更新所有依赖它的应用程序。例如,你可以改变服务器的地址,甚至服务的API,并在ESB中处理这些变化。这为你的应用程序提供了协议独立性。如果一个应用程序是使用SOAP API开发的,但一个新的服务用REST API提供了额外的功能,ESB可以使新的REST服务作为REST和SOAP API可用,允许你添加新服务的功能,同时保持对现有应用程序的兼容性。 提供一种机制来组织和跟踪企业使用的应用程序以及这些应用程序之间的依赖关系。。 ESB架构 InterSystems IRIS ESB架构有以下组成部分。 将传入的请求与服务器连接起来的路由机制。这是由具有专门业务服务(BS)和业务操作(BO)的 production实现的,也可以选择业务流程(BP)。 公共服务注册中心--这个服务注册中心可以通过ESB公共REST API被ESB客户访问。开发人员使用它来获取有关通过 ESB 可用的服务的信息。 外部服务注册中心--这个服务注册中心只能在ESB production中访问。它向ESB业务主机提供端点信息。 SAML令牌验证服务。 ESB production和服务注册处都应该被定义在一个专门用于ESB的命名空间中。 注意:InterSystems建议在一个InterSystems IRIS实例上只运行一个ESB production。 在其最简单的形式中,ESB由透传服务、透传操作和服务注册表组成。下面说明了一个简单的ESB的架构。 通常,应用程序开发人员使用网页或应用程序来查询 ESB 服务注册表,以了解可用的服务并获得提供对底层服务的访问的透传业务服务的 URL。这个查询和服务发现过程是在开发者创建客户端应用程序时进行的。一旦开发者拥有了访问服务所需的URL、文档和其它信息,客户端应用程序就不需要为了调用服务而访问服务注册表。在某些环境中,客户端应用程序可能会对公共API进行运行时调用,以确保注册表项在上次访问后没有被修改。 客户机应用程序调用透传服务。透传服务将消息发送到在其目标设置中指定的透传操作。透传操作被配置为在外部服务注册表中查找端点URL。然后,它使用该端点URL调用外部服务。外部服务将响应返回给透传操作,后者将响应指向透传服务。透传服务反过来将响应返回给客户端应用程序。 除了透传服务和操作外,你还可以定义更复杂的服务、操作和业务流程,以增加一些功能,例如,根据呼叫的内容,将呼叫从一个传入的服务路由到多个外部服务。这允许ESB提供一个单一外部服务所不能提供的服务。客户端应用程序与实现扩展服务所需的外部服务隔绝。 修改用于服务的参数或协议。如果一组应用程序是使用一种服务开发的,但后来有了具有不同 API 的高级服务,与其修改每个应用程序,不如在 ESB 中进行转换。客户端应用程序与从一个外部服务转换到另一个服务所需的变化隔绝。直接在ESB上实现服务。如果没有符合需求的外部服务,可以使用ObjectScript在ESB上实现一个。 但是,将这些更复杂的服务添加到 ESB 上有一个效率成本。这些复杂服务的额外处理成本减缓了ESB处理请求的时间,降低了吞吐量。对于需要非常高吞吐量的ESB系统,你可以通过消除持久化消息来减少处理请求的开销。持久性消息是指从透传服务发送到透传操作的对象,以及由操作返回给服务的对象。这些对象被存储在InterSystems IRIS数据库中。这些持久性的消息在跟踪和报告ESB处理的调用以及排除任何问题时非常有用。但创建这些对象需要资源,对于吞吐量非常高的系统,这些对象所需的存储量可能非常大。为了维护系统,你必须经常清除这些信息。你可以抑制对持久化消息的使用,以获得效率,但代价是降低灵活性。更多信息请参见 "在通过式服务和操作中抑制持久化消息"。 注意:如果你正在运行HealthShare产品,HealthShare服务注册表与InterSystems IRIS服务注册表不同。HealthShare服务注册表提供了与InterSystems IRIS外部服务注册表类似的功能。在大多数情况下,你应该继续使用HealthShare服务注册表,而不是使用InterSystems IRIS外部服务注册表。 配置ESB 下面包含安装和配置InterSystems IRIS的几个配置程序: 创建一个具有互操作性的命名空间,以包含ESB production和服务注册。 配置Web网关。 创建外部服务注册表条目,定义ESB所使用的外部服务的端点。 创建 ESB production,添加提供服务的业务服务和业务操作,并启动该 production。 创建通过管理门户和公共 REST API 访问公共服务注册中心所需的角色和用户。 创建将业务服务提供给客户所需的Web应用程序。 创建公共服务注册表条目,描述通过ESB访问的服务。
公告
Claire Zheng · 一月 23, 2022

欢迎中文社区新版主@黎卫东

亲爱的社区开发者们, 我很高兴地向大家介绍一位我们的新版主@黎卫东(Weidong Li)。 @黎卫东(Weidong Li)目前担任上海嘉会国际医院集成平台经理一职 以下是@黎卫东(Weidong Li)的一些自我介绍: – 我从加入嘉会之后开始了解 InterSystems 的技术以及集成平台开发。接触并使用了 InterSystems早期的Caché版本,Cube, Ensemble 并升级到了基于 Iris 的 Health Connect 平台,并深度了解这些版本的一些特性以及基于 Health Connect 打造高效的集成平台。 – 本人有超过16年的医疗信息化经验,熟悉 IHE/DICOM/HL V2/V3,有着丰富的领域知识。曾先后就职于 INFINITT,AGFA, Carestream 等主流的 HIT 公司,设计并开发过多种医疗信息系统及设计的信息集成。在目前医院,带领一个小型的团队,基于 Health Connect,从0开始设计了整个集成平台的底层架构,整体业务流程,开发流程,开发规范,发布部署规范,第三方系统接入,运维部署,运维监控以及安全体系,打造了一个安全、高效、高可用的业务中台,连接了临床、非临床、Iot、智慧医院等多个应用场景。 – InterSystems 平台是一个非常优秀的集成平台,借助该技术,给我们业务带来了非常大的便于。我也希望这么优秀的技术,能给更多的兄弟单位和合作伙伴创造价值。我也希望能够在社区与大家一起交流,分享自己的一些实践经验;同时也希望借助这个平台,向大家学习一些优秀的实践。我们一起成长,共同进步! 热烈欢迎! 感谢@黎卫东(Weidong Li),期待您成为一名优秀的新版主! 👏 Welcome @Weidong.Li ! 热烈欢迎黎老师!
文章
姚 鑫 · 七月 14, 2021

第三章 处理文件和目录名

# 第三章 处理文件和目录名 `%Library.File`类提供了几个可用于处理文件名和目录名的类方法。在大多数情况下,文件和目录不需要存在即可使用这些方法。 ## 获取文件名和目录名 `%Library.File`类提供可用于获取部分文件名和目录名的类方法。 在给定完整路径名的情况下,使用`GetDirectory()`和`GetFilename()`分别获取目录和短文件名。对于此方法,不允许使用部分目录名。 ```java DHC-APP>set filename = "e:\temp\config.txt" DHC-APP>write ##class(%File).GetDirectory(filename) E:\temp\ DHC-APP>write ##class(%File).GetFilename(filename) config.txt ``` 在给定文件名的情况下,使用`CanonicalFilename()`从根目录获取完整路径: ```java DHC-APP>set filename = "cache.dat" DHC-APP>write ##class(%File).CanonicalFilename(filename) e:\dthealth\db\dthis\data\cache.dat DHC-APP>write ##class(%File).CanonicalFilename("foo.dat") ``` 如果文件无法打开,`CanonicalFilename()`方法将返回空字符串。 给定一个目录名,使用`ComputeFullDBDir()`构造目录名的规范形式。 ```java DHC-APP>write ##class(%File).ComputeFullDBDir("foodirectory") C:\InterSystems\Cache\mgr\foodirectory\ ``` 在给定目录名的情况下,使用`GetDirectoryLength()`和`GetDirectoryPiess()`分别获取目录中的片断数和特定片断的片断数。片断可以用斜杠(`/`)或反斜杠(`\`)分隔,具体取决于操作系统。 ```java DHC-APP>set dir = "e:\temp" DHC-APP>write ##class(%File).GetDirectoryLength(dir) 2 DHC-APP>write ##class(%File).GetDirectoryPiece(dir,1) E: ``` 在给定文件名或目录名的情况下,使用`ParentDirectoryName()`获取父目录。 ```java DHC-APP>set dir = "stream" DHC-APP>write ##class(%File).ParentDirectoryName(dir) E:\DtHealth\db\dthis\data\ ```` ## 规范化文件名和目录名 `%Library.File`类提供返回规范化文件名和目录名的类方法(遵循运行服务器的操作系统的命名规则)。当通过将名称片段附加到现有名称来创建新的文件名和目录名时,这些选项非常有用。 给定一个文件名,`NormalizeFilename()`返回规范化的文件名. 给定目录名,`NormalizeDirectory()`返回规范化的目录名。 这些方法返回适合在底层操作系统上使用的规范化名称,并将尝试标准化斜杠(`/`)或反斜杠(`\`)路径分隔符。 Windows示例: ```java DHC-APP>write ##class(%File).NormalizeDirectory("stream") E:\DtHealth\db\dthis\data\stream\ DHC-APP>write ##class(%File).NormalizeFilename("c:\temp//config.txt") C:\temp\config.txt ``` UNIX示例: ```java USER>set filename = "/tmp//samples/myfile.txt" USER>write ##class(%File).NormalizeFilename(filename) /tmp/samples/myfile.txt USER>write ##class(%File).NormalizeDirectory("stream") /InterSystems/IRIS/mgr/user/stream/ ``` 在调用这些方法之一以规范化相对于指定目录的目录名或文件名时,请添加第二个参数。该目录必须存在。 Windows示例: ```java DHC-APP>write ##class(%File).NormalizeFilename("config.txt", "e:\temp") E:\temp\config.txt DHC-APP>write ##class(%File).NormalizeDirectory("stream", "") E:\DtHealth\db\dthis\data\stream\ ``` Unix示例: ```java USER>write ##class(%File).NormalizeFilename("myfile.txt", "/tmp/samples") /tmp/samples/myfile.txt USER>write ##class(%File).NormalizeDirectory("stream", "") /InterSystems/IRIS/mgr/user/stream/ ``` `SubDirectoryName()`方法类似于`NormalizeDirectory()`的双参数形式,只是参数的顺序相反。此外,该目录不需要存在。在第三个参数中传递1以添加尾部分隔符,或者传递0以省略它(默认值)。 Windows示例: ```java DHC-APP>write ##class(%File).SubDirectoryName("C:\foobar", "samples") C:\foobar\samples DHC-APP>write ##class(%File).SubDirectoryName("", "stream", 1) E:\DtHealth\db\dthis\data\stream\ ``` Unix示例: ```java USER>write ##class(%File).SubDirectoryName("/foobar", "samples") /foobar/samples USER>write ##class(%File).SubDirectoryName("", "stream", 1) /InterSystems/IRIS/mgr/user/stream/ ``` ## 用空格处理文件和目录名 对于包含空格的文件名和目录名,请使用`NormalizeFilenameWithSpaces()`,它会根据主机平台处理路径名中的空格。与规格化文件名()和规格化目录()不同,此方法只接受一个参数,不能相对于另一个目录规格化文件或目录名,也不能相对于默认目录规格化部分文件或目录名。 在Windows系统上,如果路径名包含空格,并且文件或目录不存在,则该方法返回用双引号括起来的路径名。如果路径名包含空格,并且文件或目录确实存在,则该方法返回路径名的简短形式。如果路径名不包含空格,该方法将原封不动地返回路径名。 ```java DHC-APP>write ##class(%File).NormalizeFilenameWithSpaces("C:\temp\nonexistant folder") "C:\temp\nonexistant folder" DHC-APP>write ##class(%File).NormalizeFilenameWithSpaces("C:\temp\existant folder") "C:\temp\existant folder" DHC-APP>write ##class(%File).NormalizeFilenameWithSpaces("iris.dat") iris.dat DHC-APP>write ##class(%File).NormalizeFilenameWithSpaces("cache.dat") cache.dat ``` 在Unix系统上,如果路径名包含空格,该方法将返回用双引号括起来的路径名。如果路径名不包含空格,该方法将原封不动地返回路径名。 ```java USER>write ##class(%File).NormalizeFilenameWithSpaces("/InterSystems/my directory") "/InterSystems/my directory" USER>write ##class(%File).NormalizeFilenameWithSpaces("iris.dat") iris.dat ``` ## 构建和解构文件和目录名 `%Library.File`类提供的类方法允许从路径数组构造文件名,或将文件名解构为路径数组。 给定一个路径数组,`Construct()`组装路径并返回文件名。构造的文件名适合服务器平台。在没有参数的情况下调用此方法会返回默认目录。 给定一个文件名,`Deconstruct()`分解文件名并返回一个路径数组。阵列的内容适合服务器平台。 下面的Windows示例将数组目录传递给`Construction()`。最后一个数组位置中的空字符串表示返回的文件名应以`a \`结尾。 ```java USER>zwrite dirs dirs=4 dirs(1)="C:" dirs(2)="Temp" dirs(3)="samples" dirs(4)="" USER>write ##class(%File).Construct(dirs...) C:\Temp\samples\ ``` 下面的Unix示例在不带参数的情况下调用`Construction()`。该方法返回默认目录。 ```java USER>set default = ##class(%File).Construct() USER>write default /InterSystems/IRIS/mgr/user ``` 下面的Unix示例调用`Deconstruct()`,它获取变量default中的路径并将它们存储在数组`defaultdir`中。 ```java USER>do ##class(%File).Deconstruct(default, .defaultdir) USER>zwrite defaultdir defaultdir=4 defaultdir(1)="InterSystems" defaultdir(2)="IRIS" defaultdir(3)="mgr" defaultdir(4)="user" ``` ## 获取System Manager目录 使用`ManagerDirectory()`方法获取`installdir/mgr`目录的完全限定名称。例如: ```java DHC-APP>write ##class(%File).ManagerDirectory() C:\InterSystems\Cache\mgr\ ```
文章
姚 鑫 · 三月 4, 2021

第三章 SQL语言元素(二)

# 第三章 SQL语言元素(二) # 算术运算符和函数 InterSystems SQL支持以下算术运算符: - `+` 加法操作符。 例如,`17+7 = 24`。 - `–` 减法运算符。 例如,`17-7等于10`。 注意,这些字符中的一对是InterSystems SQL注释指示器。 因此,要指定两个或多个减法操作符或负号,必须使用空格或圆括号。 例如,`17- -7或17-(-7)等于24`。 运算符 | 描述 ---|--- `+` | 加法操作符。 `–` | 减法运算符。例如,`17-7等于10`。注意,这些字符中的一对是InterSystems SQL注释指示器。因此,要指定两个或多个减法操作符或负号,必须使用空格或圆括号。 `*` |乘法运算符。例如,`17*7等于119`。 `/` | 除法操作符。例如:`17/7 = 2.428571428571428571`。 `\` | 整数除法运算符。例如,`17\7等于2`。 `#` | 模运算符。例如,`17 #7等于3`。注意,因为#字符也是一个有效的标识符字符,要将它用作模运算符,应该指定它与操作数之间用前后空格分隔 `E` | 求幂(科学记数法)运算符。可以是大写或小写。例如:`7E3 = 7000`。指数过大会导致`SQLCODE -7`“指数超出范围”错误。例如1E309、7E308。 `()`| 分组操作符。用于嵌套算术运算。除非使用了圆括号,否则在InterSystems SQL中算术操作的执行顺序是严格的从左到右的顺序。例如,`17+7*2等于48`,但`17+(7 * 2)等于31`。 `||` | 连接运算符。例如,`17||7等于177`。 算术运算是对标准形式的数字进行的。 ## 产生的数据类型 当对两个具有不同数据类型的数值执行算术运算时,结果数据类型确定如下: 对于加法(`+`),减法(`-`),整数除法(`\`),和取模(`#`): 描述 |NUMERIC| INTEGER| TINYINT| SMALLINT| BIGINT| DOUBLE ---|---|---|---|---|---|--- NUMERIC| NUMERIC| NUMERIC| NUMERIC |NUMERIC| NUMERIC |DOUBLE INTEGER |NUMERIC| BIGINT |BIGINT| BIGINT| BIGINT| DOUBLE TINYINT |NUMERIC| BIGINT| SMALLINT| INTEGER |BIGINT| DOUBLE SMALLINT| NUMERIC |BIGINT| INTEGER| INTEGER |BIGINT| DOUBLE BIGINT| NUMERIC| BIGINT| BIGINT| BIGINT| BIGINT| DOUBLE DOUBLE| DOUBLE| DOUBLE| DOUBLE| DOUBLE |DOUBLE |DOUBLE 对于乘法(`*`)或除法(`/`): 描述 |NUMERIC| INTEGER| TINYINT| SMALLINT| BIGINT| DOUBLE ---|---|---|---|---|---|--- NUMERIC| NUMERIC| NUMERIC| NUMERIC| NUMERIC| NUMERIC| DOUBLE INTEGER| NUMERIC| NUMERIC| NUMERIC| NUMERIC| NUMERIC| DOUBLE TINYINT| NUMERIC| NUMERIC| NUMERIC| NUMERIC| NUMERIC| DOUBLE SMALLINT| NUMERIC| NUMERIC| NUMERIC| NUMERIC| NUMERIC| DOUBLE BIGINT| NUMERIC| NUMERIC| NUMERIC| NUMERIC| NUMERIC| DOUBLE DOUBLE| DOUBLE| DOUBLE| DOUBLE| DOUBLE| DOUBLE |DOUBLE 连接任意数据类型的两个数字将产生VARCHAR字符串。 在动态SQL中,可以使用SQL列元数据来确定结果集字段的数据类型。 ## 运算符优先级 SQL-92标准在操作符优先级方面不精确; 关于这个问题的假设在不同的SQL实现中有所不同。 InterSystems SQL可以配置为支持任意一种优先级: - 在InterSystems IRIS 2019.1及其后续版本中,InterSystems SQL默认支持算术运算符的ANSI优先级。 这是一个系统范围的配置设置。 当配置ANSI优先级时,`"*"`、`"\"`、`"/"`和`"#"`操作符的优先级高于`"+"`、`"-"`和`"||"`操作符。 优先级高的操作符在优先级低的操作符之前执行。 因此,`3+3*5 = 18`。 如果需要,可以使用括号覆盖优先级。 因此,`(3+3)*5 = 30`。 在安装InterSystems IRIS 2019.1时,支持默认的ANSI优先级; 升级InterSystems IRIS 2018.1到InterSystems IRIS 2019.1时,操作符优先级仍然配置为InterSystems IRIS 2018.1 default:严格从左到右的顺序。 - 在InterSystems IRIS 2018.1中,InterSystems SQL默认不提供算术运算符的优先级。 默认情况下,InterSystems SQL严格按照从左到右的顺序执行算术表达式,没有操作符优先级。 这与ObjectScript中使用的约定相同。 因此,`3+3*5 = 30`。 可以使用括号来强制要求的优先级。 因此,`3+(3*5)= 18`。 谨慎的开发人员应该使用圆括号来明确地表达他们的意图。 **可以使用`$SYSTEM.SQL.SetANSIPrecedence()`方法在系统范围内配置任意一种SQL操作符优先级。 `1 = ANSI优先`; `0 =严格从左到右的计算`。** 要确定当前设置,调用`$SYSTEM.SQL.CurrentSettings()`。 更改此SQL选项将立即在系统范围内生效。 更改此选项将导致在系统范围内清除所有缓存的查询。 更改SQL优先级对ObjectScript没有影响。 ObjectScript总是严格遵循从左到右的算术运算符执行。 ## 精度和等级 数字结果的精度(数字中存在的最大数字数)为: - 使用以下算法确定加减:`resultprecision=max(scale1, scale2)+ max(precision1-scale1, precision2-scale2)+1`。 当计算结果精度大于36时,将精度值设置为36。 - 乘法使用以下算法确定:`resultprecision=min(36, precision1+precision2+1)`。 - 除法(value1 / value2)通过以下算法确定:`resultprecision=min(36, precision1-scale1 +scale2+max(6, scale1+precision2+1))`。 以下数字结果的比例(最大小数位数): - 加法或减法使用以下算法确定:`resultscale=max(scale1, scale2)`。 - 乘法使用如下算法确定:`resultscale=min(17, scale1+scale2)`。 - 除法(value1 / value2)通过如下算法确定:`resultscale=min(17, max(6, scale1+precision2+1))`。 ## 算术和三角函数 InterSystems SQL支持以下算术函数: 代码 | 描述 ---|--- ABS |返回数字表达式的绝对值。 CEILING|返回大于或等于数字表达式的最小整数。 EXP| 返回数值表达式的对数指数(以e为底)值。 FLOOR| 返回小于或等于数字表达式的最大整数。 GREATEST| 从逗号分隔的数字列表中返回最大的数字。 ISNUMERIC| 返回一个布尔码,指定表达式是否为有效数字。 LEAST| 从逗号分隔的数字列表中返回最小的数字。 LOG|返回数字表达式的自然对数(以e为基数)值。 LOG10| 返回数字表达式的以10为基数的日志值。 MOD| 返回除法运算的模值(余数)。与#操作符相同。 PI| 返回数值常量pi。 POWER| 返回数值表达式的指定幂的值 ROUND| 返回四舍五入(或截断)到指定数字数目的数字表达式。 SIGN|返回数值代码,指定数值表达式的计算结果是正、零还是负。 SQRT| 返回数值表达式的平方根。 SQUARE| 返回数值表达式的平方。 TRUNCATE|返回截断为指定数字数目的数字表达式。 InterSystems SQL支持下列三角函数。 代码 | 描述 ---|--- ACOS| 返回数值表达式的反余弦值。 ASIN| 返回数字表达式的反正弦值。 ATAN| 返回数值表达式的正切。 COS |返回数值表达式的余弦值。 COT |返回数值表达式的余切。 SIN |返回数值表达式的正弦值。 TAN |返回数值表达式的切线。 DEGREES| 将弧度转换为角度。 RADIANS |将角度转换为弧度。 # 关系运算符 条件表达式的计算结果为布尔值。条件表达式可以使用以下关系运算符: 代码 | 描述 ---|--- `=`| 等于运算符。 `!=` ``|不等于运算符。这两种句法形式在功能上是相同的。 ``| 大于运算符。 `=`| 大于或等于运算符。 比较表格字段值时,这些相等运算符将使用字段的默认排序规则。 InterSystems IRIS默认值不区分大小写。比较两个文字时,比较区分大小写。 比较浮点数时,应避免使用等号运算符(等于或不等于)。浮点数(数据类型为`%Library.Decimal`和`%Library.Double`类)存储为二进制值,而不是固定精度的数字。在转换过程中,舍入运算可能会导致两个浮点数不完全相等,这些浮点数旨在表示相同的数字。使用小于/大于测试来确定两个浮点数是否“相同”至所需的精度。 ## 包含并跟随运算符 InterSystems SQL还支持“包含”和“跟随”比较运算符: - `[` 包含运算符。返回包含操作数的所有值,包括等于该操作数的值。该运算符使用`EXACT`(区分大小写)排序规则。取反是`NOT [`。 - `Contains`运算符确定一个值是否包含指定的字符或字符串。区分大小写。 - `%STARTWITH`谓词条件确定值是否以指定的字符或字符串开头。它不区分大小写。 - InterSystems SQL搜索可用于确定值是否包含指定的单词或短语。 SQL Search执行上下文感知匹配。它不区分大小写。 - `]` 跟随运算符。返回排序规则序列中跟随操作数的所有值。排除操作数值本身。该运算符使用字段的默认排序规则。 InterSystems IRIS默认值不区分大小写。反之则不是`]`。 例如,`SELECT Age FROM MyTable,其中Age] 88`返回89或更大的值,但也返回9,因为在排序序列中9在88之后。 `SELECT Age FROM MyTable WHERE Age > 88`返回89以上; 它不会返回9。 字符串操作数,如`' ABC '`,排序在任何包含附加字符的字符串(如`' ABCA '`)之前; 因此,要从`[`操作符或`>`操作符中排除操作数字符串,必须指定整个字符串。 `Name ] ‘Smith,John’ `包含 `‘Smith,John’` 不包含 `‘Smith,John P.’` # 逻辑运算符 SQL逻辑运算符用于评估为True或False的条件表达式中。这些条件表达式在`SELECT`语句`WHERE`和`HAVING`子句,`CASE`语句`WHEN`子句,`JOIN`语句`ON`子句和`CREATE TRIGGER`语句`WHEN`子句中使用。 ## 非一元运算符 可以使用`NOT`一元逻辑运算符来指定条件的逻辑逆,如以下示例所示: ```sql SELECT Name,Age FROM Sample.Person WHERE NOT Age>21 ORDER BY Age ``` ```sql SELECT Name,Age FROM Sample.Person WHERE NOT Name %STARTSWITH('A') ORDER BY Name ``` 可以将`NOT`运算符放在条件之前(如上所示)。或者,不能将`NOT`放在单字符运算符之前;例如,`NOT =65 ORDER BY Age ``` ```sql SELECT Name,Age FROM Sample.Person WHERE Age>20 & Age=40 & (Age # 2)=0 ! Age>=65 ORDER BY Age ``` 可以使用括号将逻辑运算符分组。这将建立分组级别;评估从最低的分组级别到最高的分组级别进行。在下面的第一个示例中,“与”条件仅应用于第二个“或”条件。它返回来自MA的任何年龄的人,以及来自NY的小于25岁的人: ```sql SELECT Name,Age,Home_State FROM Sample.Person WHERE Home_State='MA' OR Home_State='NY' AND Age < 25 ORDER BY Age ``` 使用括号对条件进行分组会得出不同的结果。以下示例返回来自MA或NY的年龄小于25的人员: ```sql SELECT Name,Age,Home_State FROM Sample.Person WHERE (Home_State='MA' OR Home_State='NY') AND Age < 25 ORDER BY Age ``` - SQL执行使用短路逻辑。如果条件失败,将不会测试其余的`AND`条件。如果条件成功,则将不会测试其余的`OR`条件。 - 但是,由于SQL优化了`WHERE`子句执行,因此无法预测并且不应该依赖多个条件(在同一分组级别)的执行顺序。 # 注释 InterSystems SQL支持单行注释和多行注释。注释文本可以包含任何字符或字符串,当然,指示注释结尾的字符除外。 注意:使用嵌入式SQL标记语法`(&sql(...))` 对SQL注释的内容强加了限制。如果使用标记语法,则SQL代码中的注释可能不包含字符序列“)``”。 可以使用`preparse()`方法返回去除注释的SQL DML语句。 `preparse()`方法还用`?`替换每个查询参数。字符并返回这些参数的`%List`结构。以下示例中的`preparse()`方法返回查询的解析版本,除去单行和多行注释以及空格: ```sql /// d ##class(PHA.TEST.SQL).Null5() ClassMethod Null5() { SET myq=4 SET myq(1)="SELECT TOP ? Name /* first name */, Age " SET myq(2)=" FROM Sample.MyTable -- this is the FROM clause" SET myq(3)=" WHERE /* various conditions " SET myq(4)="apply */ Name='Fred' AND Age > 21 -- end of query" DO ##class(%SQL.Statement).preparse(.myq,.stripped,.args) WRITE stripped,! WRITE $LISTTOSTRING(args) } ``` ```sql DHC-APP>d ##class(PHA.TEST.SQL).Null5() SELECT TOP ? Name , Age FROM Sample . MyTable WHERE Name = ? AND Age > ? ?,?,c,Fred,c,21 ``` ## 单行注释 单行注释由两个连字符前缀指定。注释可以在单独的行上,也可以与SQL代码显示在同一行上。当注释在同一行上跟随SQL代码时,至少一个空格必须将代码与双连字符注释运算符分隔开。注释可以包含任何字符,包括连字符,星号和斜杠。注释继续到该行的末尾。 下面的示例包含多个单行注释: ```sql -- This is a simple SQL query -- containing -- (double hyphen) comments SELECT TOP 10 Name,Age, -- Two columns selected Home_State -- A third column FROM Sample.Person -- Table name -- Other clauses follow WHERE Age > 20 AND -- Comment within a clause Age < 40 ORDER BY Age, -- Comment within a clause Home_State -- End of query ``` ## 多行注释 多行注释由`/ * 开头定界符和 * /`结束定界符指定。注释可以出现在一个或多个单独的行上,或者可以与SQL代码在同一行上开始或结束。注释定界符应与SQL代码分隔至少一个空格。注释可以包含任何字符,包括连字符,星号和斜杠,但* /字符对显然是例外。 下面的示例包含多个多行注释: ```sql /* This is a simple SQL query. */ SELECT TOP 10 Name,Age /* Two fields selected */ FROM Sample.Person /* Other clauses could appear here */ ORDER BY Age /* End of query */ ``` 当注释掉嵌入式SQL代码时,请始终在`&sql`指令之前或括号内开始注释。下面的示例正确注释掉了两个嵌入式SQL代码块: ```sql SET a="default name",b="default age" WRITE "(not) Invoking Embedded SQL",! /*&sql(SELECT Name INTO :a FROM Sample.Person) */ WRITE "The name is ",a,! WRITE "Invoking Embedded SQL (as a no-op)",! &sql(/* SELECT Age INTO :b FROM Sample.Person */) WRITE "The age is ",b ``` ## SQL代码保留为注释 嵌入式SQL语句可以保留为例程的.INT代码版本中的注释。这是通过设置`$SYSTEM.SQL.SetRetainSQL()`方法完成的。若要确定当前设置,请调用`$ SYSTEM.SQL.CurrentSettings()`,它将显示“将SQL保留为注释”设置。默认值为1(“是”)。 将此选项设置为“是”以将SQL语句保留为例程的.INT代码版本中的注释。将此选项设置为“是”还会在注释文本中列出SQL语句使用的所有非%变量。这些列出的变量也应该在ObjectScript过程的PUBLIC变量列表中列出,并使用NEW命令重新初始化。 有用 欢迎来投票:) 讲的很细,非常有帮助! 非常不错的学习资料,十分感谢! 技术博主👍
文章
姚 鑫 · 五月 8, 2021

第三章 使用多维存储(全局变量)(四)

# 第三章 使用多维存储(全局变量)(四) # 管理事务 InterSystems IRIS提供了使用全局变量实现完整事务处理所需的基本操作。 InterSystems IRIS对象和SQL自动利用这些特性。 如果直接将事务性数据写入全局变量,则可以使用这些操作。 事务命令是`TSTART`,它定义事务的开始; `TCOMMIT`,它提交当前事务; 和`TROLLBACK`,它将中止当前事务,并撤消自事务开始以来对全局变量所做的任何更改。 例如,下面的ObjectScript代码定义了事务的开始,设置了一些全局变量节点,然后根据`ok`的值提交或回滚事务: ```java /// w ##class(PHA.TEST.Global).GlobalTro(0) ClassMethod GlobalTro(ok) { TSTART Set ^Data(1) = "Apple1" Set ^Data(2) = "Berry1" If (ok) { TCOMMIT } Else { TROLLBACK } zw ^Data q "" } ``` TSTART在InterSystems IRIS日志文件中写入事务开始标记。 这定义了事务的起始边界。 在上面的示例中,如果变量`ok`为`true`(非零),则`TCOMMIT`命令标记事务成功结束,并将事务完成标记写入日志文件。 如果`ok`为`false(0)`,那么`TROLLBACK`命令将撤消自事务开始以来进行的每一个`set`或`kill`操作。 在这种情况下,`^Data(1)`和`^Data(2)`被恢复到原来的值。 **注意,在事务成功完成时,不会写入任何数据。 这是因为事务期间对数据库的所有修改都是在事务过程中正常执行的。 只有在回滚的情况下,数据库中的数据才会受到影响。 这意味着本例中的事务具有有限的隔离性; 也就是说,其他进程可以在事务提交之前看到修改后的全局值。 这通常被称为未提交的读取。 这是好是坏取决于应用程序的需求; 在许多情况下,这是完全合理的行为。 如果应用程序需要更高级别的隔离,则可以通过使用锁来实现。 这将在下一节中进行描述。** ## 锁和事务 要创建隔离事务-也就是说,为了防止其他进程在提交事务之前看到修改的数据-需要使用锁。在ObjectScript中,可以通过`lock`命令直接获取和释放锁定。锁按照约定工作;对于给定的数据结构(如用于持久对象),所有需要锁的代码都使用相同的逻辑锁引用(即,锁命令使用相同的地址)。 在事务中,锁有一个特殊的行为; 在事务过程中获取的任何锁在事务结束之前都不会被释放。 要了解为什么会这样,请考虑典型事务执行的操作: 1. 使用`TSTART`启动事务。 2. 获取要修改的一个或多个节点上的锁。这通常被称为“写”锁。 3. 修改一个或多个节点。 4. 释放锁(或多个锁)。因为我们处于事务中,所以这些锁在此时实际上不会被释放。 5. 使用`TCOMMIT`提交事务。此时,上一步中释放的所有锁实际上都已释放。 如果另一个进程想要查看此事务中涉及的节点,并且不想看到未提交的修改,则它只需在从节点读取数据之前测试锁(称为“读”锁)。因为写锁定一直保持到事务结束,所以在事务完成(提交或回滚)之前,读取进程看不到数据。 大多数数据库管理系统使用类似的机制来提供事务隔离。InterSystems IRIS的独特之处在于它让开发人员可以使用这种机制。这使得有可能为新的应用程序类型创建自定义数据库结构,同时仍然支持事务。当然,可以简单地使用InterSystems IRIS对象或SQL来管理数据,并让事务得到自动管理。 ## 对TSTART的嵌套调用 InterSystems IRIS维护一个特殊的系统变量`$TLEVEL`,该变量跟踪`TSTART`命令被调用的次数。`$TLEVEL`从值`0`开始;每次调用`TSTART`时,`$TLEVEL`的值递增`1`,而每次调用`TCOMMIT`时,`$TLEVEL`的值递减`1`。如果调用`TCOMMIT`导致将`$TLEVEL`设置回`0`,则事务结束(以`COMMIT`结束)。 调用`TROLLBACK`命令总是终止当前事务,并将`$TLEVEL`设置回`0`,而不管`$TLEVEL`的值是多少。 此行为使应用程序能够将事务包装在本身包含事务的代码(如对象方法)周围。例如,持久对象提供的`%Save`方法始终将其操作作为事务执行。通过显式调用`TSTART`和`TCOMMIT`,可以创建包含几个对象保存操作的更大事务: ```java TSTART Set sc = object1.%Save() If ($$$ISOK(sc)) { // 第一次保存有效,执行第二次保存 Set sc = object2.%Save() } If ($$$ISERR(sc)) { // 其中一个保存失败,正在回滚 TROLLBACK } Else { // 提交 TCOMMIT } ``` # 管理并发性 设置或检索单个全局变量节点的操作是原子的;它可以保证始终成功并获得一致的结果。对于多个节点上的操作或控制事务隔离,InterSystems IRIS提供获取和释放锁的功能。 锁由IRIS锁管理器管理。在ObjectScript中,可以通过`lock`命令直接获取和释放锁定。(InterSystems IRIS对象和SQL根据需要自动获取和释放锁)。 # 检查最新的全局变量引用 **最新的全局变量引用记录在ObjectScript `$ZREFERENCE`特殊变量中。`$ZREFERENCE`包含最新的全局引用,包括下标和扩展全局引用(如果指定)。请注意,`$ZREFERENCE`既不指示全局引用是否成功,也不指示指定的全局是否存在。InterSystems IRIS只记录最近指定的全局引用。** ## 裸全球变量引用 在带下标的全局引用之后,InterSystems IRIS会将裸指示符设置为该全局名称和下标级别。然后,可以使用裸全局引用(省略全局名称和更高级别的下标)对相同的全局变量和下标级别进行后续引用。这简化了在相同(或更低)下标级别对相同全局变量的重复引用。 在裸引用中指定较低的下标级别会将裸指示符重置为该下标级别。因此,在使用裸全局变量引用时,始终使用由最新全局引用建立的下标级别。 裸指示符值记录在`$ZREFERENCE`特殊变量中。裸露指示符被初始化为空字符串。在未设置裸指示器的情况下尝试裸全局引用会导致`` 错误。更改命名空间会重新初始化裸体指示符。可以通过将`$ZREFERENCE`设置为空字符串(`“”`)来重新初始化裸指示符。 在下面的示例中,第一个引用中指定了带下标的GLOBAL `^Produce(“fruit”,1)`。InterSystems IRIS将此全局变量名称和下标保存在裸体指示符中,以便后续的裸体全局引用可以省略全局名称`“Production”`和更高下标级别的`“Fruit”`。当`^(3,1)`裸引用达到更低的下标级别时,此新的下标级别将成为任何后续裸全局变引用的假设。 ```java /// w ##class(PHA.TEST.Global).GlobalNake() ClassMethod GlobalNake() { SET ^Produce("fruit",1)="Apples" /* 完整的全局变量引用 */ SET ^(2)="Oranges" /* 裸全局变量全局引用 */ SET ^(3)="Pears" /* 假设下标级别为2 */ SET ^(3,1)="Bartlett pears" /* 转到下标级别3 */ SET ^(2)="Anjou pears" /* 假设下标级别为3 */ WRITE "latest global reference is: ",$ZREFERENCE,! ZWRITE ^Produce KILL ^Produce q "" } ``` ```java DHC-APP>w ##class(PHA.TEST.Global).GlobalNake() latest global reference is: ^Produce("fruit",3,2) ^Produce("fruit",1)="Apples" ^Produce("fruit",2)="Oranges" ^Produce("fruit",3)="Pears" ^Produce("fruit",3,1)="Bartlett pears" ^Produce("fruit",3,2)="Anjou pears" ``` 除了极少数例外,每个全局变量变引用(全引用或裸引用)都会设置裸指示器。`$ZREFERENCE`特殊变量包含最新全局变引用的完整全局名称和下标,即使这是一个裸全局引用。`ZWRITE`命令还显示每个全局的完整全局名称和下标,无论它是否使用裸引用设置。 应谨慎使用裸全局变量引用,因为InterSystems IRIS在不总是明显的情况下设置裸指示器,包括以下情况: - 完整全局变量引用最初设置裸露指示符,随后的完整全局引用或裸露全局引用会更改裸露指示符,即使全局引用不成功。例如,试图写入不存在的全局变量的值会设置裸指示符。 - 无论InterSystems IRIS如何计算后置条件,引用下标全局的后置条件命令都会设置裸指示符。 - 引用下标全局变量的可选函数参数可能设置或不设置裸指示符,具体取决于IRIS是否计算所有参数。例如,`$get`的第二个参数总是设置裸指示符,即使它包含的默认值没有使用。InterSystems IRIS按从左到右的顺序计算参数,因此最后一个参数可能会重置由第一个参数设置的裸指示符。 - 回滚事务的`TROLLBACK`命令不会将裸指示符回滚到事务开始时的值。 如果完整全局变量引用包含扩展全局变量引用,则后续的裸全局变量引用将采用相同的扩展全局引用;不必将扩展引用指定为裸全局引用的一部分。
问题
Botai Zhang · 四月 13, 2021

编码格式转换

在使用过程中,碰到对接一些国内编码例如:GBK2312等系列的编码格式,碰到这类情况,应该如何处理?各位有没有好的解决方式?期待解答交流! 如果需要在InterSystems IRIS中对不同的编码的数据进行转换,可以使用函数$ZCVT。 例如将变量tStr的unicode值转换为GB2312: s tOutput=$ZCVT(tStr,"O","GB2312") 感谢回复!这种方式尝试过,但是,$ZCVT并不支持GB2312。 用GB18030,它向后兼容GB2312
公告
Michael Lei · 六月 22, 2022

CloudStudio - 一个纯浏览器的代码编辑器

Hi 社区, 这是海外工程师做的一个纯浏览器的代码编辑器CloudStudio. 欢迎大家下载试用: GitHub 下载: https://github.com/SeanConnelly/CloudStudio InterSystems 应用市场下载:https://openexchange.intersystems.com/package/CloudStudio 到Discord 讨论区:https://discord.gg/ZnvdMywsjP Docker 支持与在线Demo: 要求 已安装 git 和 Docker desktop . 安装 Clone/git 把 repo 导入任何本地目录 git https://github.com/rcemper/Dataset-OEX-reviews.git 启动IRIS容器: docker-compose up -d --build 如何测试 http://localhost:42773/cloudstudio/CloudStudio.Index.cls 或使用在线Demo Demo 视频:https://www.youtube.com/watch?v=Am6QAvrPPPg
公告
Claire Zheng · 十一月 22, 2021

参与Gartner Peer Insights同业评审,赢取价值$25的礼品卡

亲爱的社区开发者们,大家好! 现在参与Gartner Peer Insight同业评审对我们的产品做出评价,可获得价值 $25 美元的礼品卡。评论观点需中立客观(InterSystems员工不允许参加)并被Gartner审核通过。点击此处开始: https://gtnr.it/3ulVX4K 。 对流程不熟悉的同学,可以参考一下我们此前发布的一篇旧贴。 调研仅花费您很少时间,欢迎大家积极参与! 活动已经截止了。。。
公告
Claire Zheng · 三月 11, 2021

欢迎中文社区新版主@姚鑫

亲爱的社区开发者们, 我很高兴地向大家介绍一位我们的新版主@姚鑫 @姚鑫是东华医为的一名开发工程师。 以下是@姚鑫的自我介绍: 大家好,我非常热衷于与开发者们分享我的技术经验。作为一名移动端全栈开发工程师,我发表了《Caché 23种设计模式》《Caché 算法与数据结构》《Caché 从入门到精通》《疯狂 Caché》《Caché 命令大全》《Caché 函数大全》《Caché 变量大全》《Caché SQL 必知必会》等一系列文章集。 在CSDN(中国最大的开发者社区之一),我被认证为博客专家,CSDN优秀讲师。 在掘金网这个帮助开发者成长的知名社区,获得了2020年掘金十大年度人气作者称号。 我很荣幸能够加入InterSystems开发者社区(中文版)并参与到社区管理、运营中,希望可以同使用InterSystems技术的开发者更好地交流、共同成长。 感谢@姚鑫,恭喜你成为新版主! 感谢@姚鑫!期待更多大作! 欢迎新版主@姚鑫 欢迎新版主@姚鑫期待将来分享更多关于IRIS数据平台的经验
文章
Lele Yang · 六月 8, 2021

FAQ 常见问题系列--应用篇 升级系统后打开管理门户SMP报错5001

如果您在升级了系统之后,打开SMP时看到如下报错,ERROR #5001: 对象的服务器版本与客户端发送的版本不一致: %ZEN.Component.vgroup 一般情况下,这个报错是由浏览器缓存中残留的过期信息造成的,可以通过清除浏览器缓存来解决。 如果清除浏览器缓存之后仍然未能解决此问题,请您前往系统安装目录, 如:d:\InterSystems\IRIS\CSP\broker,查看css/js文件的时间戳在本次更新安装之后是否并没有相应地更新,如果没有,请您做以下尝试,1)在IRIS中更改数据库IRISLIB, 之前的版本是CACHELIB, 取消只读装载,方法如下,打开管理门户SMP, 系统管理->配置->本地数据库,选择要更改的数据库,取消"只读方式挂载",点击【保存】。2)重新编译%Zen组件,w ##class(%SYSTEM.OBJ).Compile("%ZEN.Component.vgroup")此时,再次前往,d:\InterSystems\IRIS\CSP\broker,会看到相关的css/js文件时间戳已经更新。3)恢复上述数据库的只读装载。 如果以上办法仍然未能解决您的问题,建议您联系WRC,寻求Support的进一步帮助。
文章
Michael Lei · 八月 10, 2023

如何比较两个数据库中的多个Global和Routines

InterSystems 常见问题解答 ※如果您想比较使用Mirror、Shadow或其他机制复制的数据库,请使用此方法。 您可以使用 DATACHECK 实用程序来比较Global。请参阅下面的文档。DataCheck 概述 [IRIS] *** Routines比较使用系统例程 %RCMP 或管理门户。 以下是如何在管理门户中使用它。 例如,假设以下Routine位于 USER 命名空间中。 test() public{ quit "hello" } 假设以下Routine位于 USER2 命名空间中。 test() public{ quit "Hello" } 下面是在连接到 USER 命名空间的终端中运行 %RCOM 的结果。 * 在Compare : 中写入Routine名称以及要与: 进行比较的Routine名称要指定另一个命名空间中的Routine,请指定|“命名空间名称”|例程名称.MAC。 用户>执行 ^%RCMP比较:comptest.mac 与:|"USER2"|comptest.macCompare: // [备注] 如果没有可比较的内容,请按 Enter忽略评论差异?否 => 否忽略前导空格?否 => 否显示结果于Device: c:\temp\comp.txt // [备注] 指定文件名时的文件输出 参数? (“WNS”)=>comptest.MAC |“USER2”|comptest.MAC****************************************************** ******************************用户> 对比结果如下。 常规比较 2021 年 2 月 2 日 2:31 PM来自目录:c:\intersystems\iris\mgr\user\ comptest.MAC |“USER2”|comptest.MAC****************************************************** ******************************竞争测试.MAC+2 退出“你好”......................|“USER2”|comptest.MAC+2 退出“你好”****************************************************** **************************
文章
姚 鑫 · 七月 10, 2022

第一章 嵌入式Python概述(一)

# 第一章 嵌入式Python概述(一) 嵌入式 `Python` 允许将 `Python` 与 IRIS 数据平台的本地编程语言 `ObjectScript` 一起使用。当使用嵌入式 `Python` 在 `IRIS` 类中编写方法时,`Python` 源代码与编译后的 `ObjectScript` 代码一起编译为在服务器上运行的目标代码。与使用网关或 `Python`的 `Native SDK` 相比,这允许更紧密的集成。还可以导入 `Python` 包,无论它们是自定义的还是公开的,并在`ObjectScript` 代码中使用它们。 `Python` 对象是 `ObjectScript` 中的一等公民,反之亦然。 - 使用来自 `ObjectScript` 的 `Python` 库 - 此方案假设 `ObjectScript` 开发人员,并且希望利用 `Python` 开发人员社区可用的众多 `Python` 库的强大功能。 - 从 `Python` 调用 `IRIS API` — 此方案假定您是一名 `Python` 开发人员,对 IRIS 不熟悉,并且想知道如何访问 `API`。 - 一起使用 `ObjectScript` 和 `Python` — 这个场景假设在一个由 `ObjectScript` 和 `Python` 开发人员组成的混合团队中,并且想知道如何一起使用这两种语言。 将需要 `2021.2` 或更高版本的正在运行的 `IRIS` 实例,以及取决于操作系统的一些先决条件。还需要知道如何访问终端,即 `IRIS` 命令行工具。 本文档中的一些示例使用来自 `GitHub` 上 `Samples-Data` 存储库的类:`https://github.com/intersystems/Samples-Data`。 建议创建一个名为 `SAMPLES` 的专用命名空间并将样本加载到该命名空间中。如果想查看或修改示例代码,则需要设置集成开发环境 (`IDE`)。推荐使用 `Visual Studio Code`。 本篇并不试图提供嵌入式 `Python` 或使用 `IRIS` 进行编程的全面概述。 # 使用 ObjectScript 中的 Python 库 使用 `Embedded Python`,`ObjectScript` 开发人员可以轻松地使用来自 `IRIS` 的众多可用 `Python` 库(通常称为“包”)中的任何一种,从而无需开发自定义库来复制现有功能。 `IRIS` 在 `/mgr/python` 目录中查找已安装的 `Python` 包 从 `ObjectScript` 准备 `Python` 包以供使用是一个两步过程: 1. 从命令行,从 `Python` 包索引(或其他索引)安装所需的包。 2. 在 `ObjectScript` 中,导入已安装的包以加载包并将其作为对象返回。然后,可以像使用实例化的 `ObjectScript` 类一样使用该对象。 ## 安装 Python 包 在将 `Python` 包与 `Embedded Python` 一起使用之前,请从命令行安装。使用的命令会有所不同,具体取决于使用的是 `Windows` 还是基于 `UNIX` 的系统。 建议将软件包安装到目录 `/mgr/python`。 在 `Windows` 上,使用 `/bin` 目录中的 `irispip` 命令:`irispip install --target \mgr\python `. 例如,可以在 `Windows` 机器上安装 `numpy` 包,如下所示: ```java C:\InterSystems\IRIS\bin>irispip install --target C:\InterSystems\IRIS\mgr\python numpy ``` 在基于 `UNIX` 的系统上,使用 `pip3` 命令:`pip3 install --target /mgr/python `。 例如,可以在 Linux 机器上安装 `numpy` 包,如下所示: ```java $ pip3 install --target /InterSystems/IRIS/mgr/python numpy ``` 注意:如果基于 `UNIX` 的系统没有安装 `pip3`,请使用系统的包管理器安装包 `python3-pip`。 ## 导入 Python 包 `%SYS.Python` 类包含从 `ObjectScript` 使用 `Python` 所需的功能。可以在任何 `ObjectScript` 上下文中使用 `%SYS.Python`,例如类、终端会话或 `SQL`。 要从 ObjectScript 导入 `Python` 包或模块,请使用 `%SYS.Python.Import()` 方法。 例如,假设在 `USER` 命名空间中,以下命令会在终端中导入数学模块: ```java USER>set pymath = ##class(%SYS.Python).Import("math") ``` 数学模块与标准 `Python` 版本打包在一起,因此无需在导入之前安装它。通过在 `pymath` 对象上调用 `zwrite`,可以看到它是内置数学模块的一个实例: ```java USER>zwrite pymath pymath=1@%SYS.Python ; ; ``` 注意:包是 `Python` 模块的集合,但是当导入包时,创建的对象始终是模块类型。 现在,可以像访问任何 `ObjectScript` 对象一样访问数学模块属性和方法: ```java USER>write pymath.pi 3.141592653589793116 USER>write pymath.factorial(10) 3628800 ``` # 示例 此示例使用 `geopy` 包来访问 `OpenStreetMap` 的 `Nominatim` 地理编码工具。地理编码是获取基于文本的位置描述(例如地址或地名)并返回地理坐标(例如纬度和经度)以精确定位地球表面位置的过程。 首先,从命令行安装 `geopy`,如下 `Windows` 示例所示: ```java C:\InterSystems\IRIS\bin>irispip install --target C:\InterSystems\IRIS\mgr\python geopy Collecting geopy Using cached geopy-2.2.0-py3-none-any.whl (118 kB) Collecting geographiclib=1.49 Using cached geographiclib-1.52-py3-none-any.whl (38 kB) Installing collected packages: geographiclib, geopy Successfully installed geographiclib-1.52 geopy-2.2.0 ``` 在基于 UNIX 的系统上,使用: ```java $ pip3 install --target /InterSystems/IRIS/mgr/python geopy ``` 然后在终端中运行以下命令来导入和使用模块: ```java USER>set geopy = ##class(%SYS.Python).Import("geopy") USER>set args = { "user_agent": "Embedded Python" } USER>set geolocator = geopy.Nominatim(args...) USER>set flatiron = geolocator.geocode("175 5th Avenue NYC") USER>write flatiron.address Flatiron Building, 175, 5th Avenue, Flatiron District, Manhattan, New York County, New York, 10010, United States USER>write flatiron.latitude _ "," _ flatiron.longitude 40.74105919999999514,-73.98964162240997666 USER>set cityhall = geolocator.reverse("42.3604099,-71.060181") USER>write cityhall.address Government Center, Cambridge Street, Downtown Crossing, West End, Boston, Suffolk County, Massachusetts, 02203, United States ``` 此示例将 `geopy` 模块导入 `ObjectScript`。然后它使用 `Nominatim` 模块创建一个地理定位器对象。该示例使用地理定位器的 `geocode()` 方法在给定字符串的情况下查找地球上的位置。然后它调用 `reverse()` 方法来查找给定纬度和经度的地址。 需要注意的一点是 `Nominatim()` 采用命名关键字参数,ObjectScript 不直接支持这种结构。解决方案是创建一个包含参数列表的 `JSON` 对象(在这种情况下将 `user_agent` 关键字设置为值“嵌入式 Python”),然后使用 `args...` 语法将其传递给方法。 与前面示例中导入的数学模块相比,对 `geopy` 对象调用 `zwrite` 表明它是安装在 `C:\InterSystems\iris\mgr\python` 中的 `geopy` 包的一个实例: ```java USER>zwrite geopy geopy=2@%SYS.Python ; ; ```
文章
Michael Lei · 六月 26, 2022

从Web 应用端用代码实现OAuth2 和基础认证、鉴权和审计

在这篇文章中,我将解释如何通过使用CSP Web应用程序以及启用/禁用和认证/取消认证任何Web应用程序的代码来进行认证、授权和审计。 在线 Demo -- https://dappsecurity.demo.community.intersystems.com/csp/user/index.csp (SuperUser | SYS) 推荐大家看下这个视频: https://www.youtube.com/watch?v=qFRa3njqDcA 应用层 从认证开始 认证可以验证任何试图连接到InterSystems IRIS®的用户或其他实体的身份。正如人们常说的,认证是你如何证明你是你所说的人。 有许多不同的方法可以对用户进行认证;每一种方法都被称为认证机制。InterSystems IRIS支持一系列的认证机制: Kerberos — Kerberos协议被设计用来在不安全的网络上为服务提供安全认证。Kerberos使用Ticket来验证用户,避免了在网络上交换密码。 Operating System–Based — 基于操作系统的认证使用操作系统对每个用户的身份认证来识别该用户对InterSystems IRIS的身份。 Instance Authentication — 通过实例验证,InterSystems IRIS提示用户输入密码,并将所提供的密码的哈希值与它所存储的值进行比较。 Lightweight Directory Access Protocol (LDAP) — 通过轻量级目录访问协议LDAP,InterSystems IRIS根据LDAP服务器中的信息对用户进行认证。 Delegated Authentication — 委托认证提供了一种创建自定义认证机制的方法。应用程序开发人员完全控制委托认证代码的内容。 我使用实例验证,对于用户的创建,我们可以使用以下objectscript命令: &sql(CREATE USER TestUser IDENTIFY BY demo) 创建 TestUser 和 demo 密码 审计Auditing 在创建用户记录时,也通过使用以下objectscript命令添加到审计数据库中: Do $SYSTEM.Security.Audit("%System","%Security","UserChange","User:TestUser | Password:demo","Audit Log inserted from Data_APP_Security") 请参考审计相关的文档 (Auditing Guide) : https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AAUDIT 授权Authorization 一旦认证完成,我们需要创建角色并授予角色以权限,然后将角色与用户联系起来(授权)。我们将分三步来做这件事 第一步 : 通过使用以下objectscript命令创建角色,我们正在创建ReadWrite角色 &sql(CREATE ROLE ReadWrite) 第二步: 在表上授予SELECT,UPDATE,INSERT权限,我们将scw.Patient表的权限分配给ReadWrite角色。 &sql(GRANT SELECT,UPDATE,INSERT ON scw.Patient TO ReadWrite) 第三步: 给用户授予角色,我们给TestUser用户分配ReadWrite角色 &sql(GRANT ReadWrite To TestUser) 启用/禁用Web应用 我们可以通过使用以下objectscript代码启用或禁用Web应用程序 New $Namespace Set $Namespace = "%SYS" Set App = ##class(Security.Applications).%OpenId("/terminal") Set App.Enabled=0 Do App.%Save() 这里"/终端 "是我们应用程序的名称。应用程序可以通过设置 "App.Enabled "为0来禁用,通过设置值为1来启用 认证/取消 Web 应用 我们可以通过使用以下objectscript代码来设置认证 New $Namespace Set $Namespace = "%SYS" Set App = ##class(Security.Applications).%OpenId("/terminal") Set App.AutheEnabled=0 Do App.%Save() 这里"/终端 "是我们应用程序的名称。认证可以通过使用"App.AutheEnabled" 属性来设置. 可以设置以下数值 property AutheEnabled as Security.Datatype.Authentication [ InitialExpression = 64 ]; Authentication and Session mechanisms enabled (CSP Only). Bit 2 = AutheK5API Bit 5 - AutheCache Bit 6 = AutheUnauthenticated Bit 11 = AutheLDAP Bit 13 = AutheDelegated Bit 14 = LoginToken Bit 20 = TwoFactorSMS Bit 21 = TwoFactorPW 谢谢 源代码:https://openexchange.intersystems.com/package/Data_APP_Security
文章
姚 鑫 · 四月 5, 2021

第十七章 使用触发器

# 第十七章 使用触发器 本章介绍如何在Intersystems SQL中定义触发器。触发器是响应某些SQL事件执行的代码行。本章包括以下主题: # 定义触发器 有几种方法可以为特定表定义触发器: - 在将投影到SQL表的持久性类定义中包含触发定义。例如,`MyApp.person`类的此定义包括`Loggevent`触发器的定义,在每个成功的数据插入到`MyApp.person`表之后,将在每个成功的数据插入后调用: ```java Class MyApp.Person Extends %Persistent [DdlAllowed] { // ... Class Property Definitions Trigger LogEvent [ Event = INSERT, Time = AFTER ] { // Trigger code to log an event } } ``` - 使用SQL创建触发命令创建触发器。这在相应的持久性类中生成触发对象定义。 SQL触发器名称按照标识符命名约定进行操作。 IntersystemsIris®数据平台使用SQL触发名称生成相应的触发类实体名称。 必须拥有`%create_trigger`管理级别权限来创建触发器。必须具有删除触发器的`%drop_trigger`管理级别权限。 **类的最大用户定义触发器数为200。** 注意:Intersystems Iris不支持收集投影的表上的触发。用户无法定义这样的触发器,并且作为子表的集合的投影不认为涉及该基本集合的触发。 Intersystems Iris不支持修改`Security.Roles`和`Security.Users`表的触发器。 # 触发器的类型 触发器由以下内容定义: - 导致它执行的事件类型。触发器可以是单个事件触发器或多事件触发。定义单个事件触发器以在指定表上发生插入,更新或删除事件时执行。定义多事件触发器以执行当在指定的表中发生多个指定的事件中的任何一个时执行。可以使用类定义或创建触发命令定义插入/更新,更新/删除或插入/更新/删除多事件触发器。事件类型在Class定义中指定了所需的事件触发器关键字。 - 触发器执行的时间:在事件发生之前或之后。 这是由可选的`Time trigger`关键字在类定义中指定的。 默认为`Before`。 - 可以将多个触发器与同一事件和时间相关联;在这种情况下,可以使用`order trigger`关键字来控制触发多个触发器的顺序。先触发顺序较低的触发器。 如果多个触发器具有相同的`Order`值,则不指定它们的触发顺序。 - 可选的`Foreach trigger`关键字提供了额外的粒度。 该关键字控制触发器是每一行触发一次(`Foreach = row`),还是每一行或对象访问触发一次(`Foreach = row/object`),还是每语句触发一次(`Foreach = statement`)。 没有`Foreach trigger`关键字定义的触发器每一行触发一次。 如果触发器是用`Foreach = row/object`定义的,那么触发器也会在对象访问期间的特定点被调用,如本章后面所述。 可以使用`INFORMATION.SCHEMA.TRIGGERS`的`ACTIONORIENTATION`属性列出每个触发器的`Foreach`值 下面是可用的触发器及其等价的回调方法: - `BEFORE INSERT` (等价于 `%OnBeforeSave()`) - `AFTER INSERT` (等价于 `%OnAfterSave()`) - `BEFORE UPDATE` (等价于 `%OnBeforeSave()`) - `AFTER UPDATE` (等价于 `%OnAfterSave()`) - `BEFORE UPDATE OF specified column(s)` - `AFTER UPDATE OF specified column(s)` - `BEFORE DELETE` (等价于 `%OnDelete()`) - `AFTER DELETE` (等价于 `%OnAfterDelete()`) 注意:当触发器执行时,它不能直接修改正在处理的表中的属性值。 这是因为InterSystems IRIS在字段(属性)值验证代码之后执行触发代码。 例如,触发器不能将LastModified字段设置为正在处理的行中的当前时间戳。 但是,触发器代码可以对表中的字段值发出更新。 更新执行自己的字段值验证。 ## AFTER Triggers 在`INSERT`、`UPDATE`或`DELETE`事件发生后执行`AFTER`触发器: - 如果`SQLCODE=0`(事件成功完成),InterSystems IRIS将执行`AFTER`触发器。 - 如果`SQLCODE`是负数(事件失败),系统间IRIS就不会执行`AFTER`触发器。 - 如果`SQLCODE=100`(没有发现要插入、更新或删除的行),则系统间IRIS执行`AFTER`触发器。 ## 递归触发器 触发器执行可以是递归的。 例如,如果表`T1`有一个对表`T2`执行插入操作的触发器,表`T2`也有一个对表`T1`执行插入操作的触发器。 当表`T1`有一个调用例程/过程的触发器,并且该例程/过程执行对`T1`的插入操作时,也可以发生递归。 触发器递归的处理取决于触发器的类型: - 行和行/对象触发器:InterSystems IRIS不阻止行触发器和行/对象触发器递归地执行。 处理触发器递归是程序员的责任。 如果触发代码不处理递归执行,则可能发生runtime ``错误。 - 语句触发器:InterSystems IRIS阻止`AFTER`语句触发器递归执行。 如果InterSystems IRIS检测到该触发器在执行堆栈中已经被调用,它将不会发出AFTER触发器。 没有错误发出; 触发器不会被第二次执行。 InterSystems IRIS不会阻止`BEFORE`语句触发器递归地执行。 在触发递归之前处理是程序员的责任。 如果`BEFORE`触发器代码不处理递归执行,可能会发生runtime ``错误。 # Trigger Code 每个触发器包含执行触发操作的一行或多行代码。 每当与触发器关联的事件发生时,SQL引擎就会调用这段代码。 如果触发器是使用CREATE触发器定义的,则可以用ObjectScript或SQL编写此操作代码。 (InterSystems IRIS将SQL编写的代码转换为类定义中的ObjectScript。) 如果触发器是使用Studio定义的,那么这个操作代码必须用ObjectScript编写。 因为触发器的代码不是作为过程生成的,所以触发器中的所有局部变量都是公共变量。 这意味着触发器中的所有变量都应该用一个新语句显式声明; 这可以防止它们与调用触发器的代码中的变量发生冲突。 ## %ok, %msg, and %oper 系统变量 - `%ok`:仅在触发器代码中使用的变量。 如果触发代码成功,它设置`%ok=1`。 如果触发代码失败,它设置`%ok=0`。 如果在触发器执行期间发出`SQLCODE`错误,InterSystems IRIS将设置`%ok=0`。 当`%ok=0`时,触发器代码中止,触发器操作和调用触发器的操作被回滚。 如果插入或更新触发器代码失败,并且表中定义了一个外键约束,InterSystems IRIS将释放外键表中相应行上的锁。 触发代码可以显式设置`%ok=0`。 这会创建一个运行时错误,中止触发器的执行并回滚操作。 通常,在`设置%ok=0`之前,触发器代码显式地将`%msg`变量设置为用户指定的字符串,用于描述这个用户定义的触发器代码错误。 `%ok`变量是一个必须显式更新的公共变量。 在完成非触发代码`SELECT`、`INSERT`、`UPDATE`或`DELETE`语句后,`%ok`的值与之前的值没有变化。 `%ok`仅在执行触发器代码时定义。 `%msg`:触发代码可以显式地将`%msg`变量设置为描述运行时错误原因的字符串。 设置变量`%msg`。 `%oper`:仅在触发器代码中使用的变量。 触发器代码可以引用变量`%oper`,该变量包含触发触发器的事件(插入、更新或删除)的名称。 ## {fieldname}语法 在触发器代码中,可以使用特殊的`{fieldname}`语法引用字段值(对于属于触发器关联的表的字段)。 例如,下面是`MyApp`中`LogEvent`触发器的定义。 `Person`类包含一个对`ID`字段的引用,如`{ID}`: ```java Class MyApp.Person Extends %Persistent [DdlAllowed] { // ... Definitions of other class members /// This trigger updates the LogTable after every insert Trigger LogEvent [ Event = INSERT, Time = AFTER ] { // get row id of inserted row NEW id,SQLCODE,%msg,%ok,%oper SET id = {ID} // INSERT value into Log table &sql(INSERT INTO LogTable (TableName, IDValue) VALUES ('MyApp.Person', :id)) IF SQLCODE