清除过滤器
公告
Claire Zheng · 十一月 22, 2021
亲爱的社区开发者们,大家好!
现在参与Gartner Peer Insight同业评审对我们的产品做出评价,可获得价值 $25 美元的礼品卡。评论观点需中立客观(InterSystems员工不允许参加)并被Gartner审核通过。点击此处开始: https://gtnr.it/3ulVX4K 。
对流程不熟悉的同学,可以参考一下我们此前发布的一篇旧贴。
调研仅花费您很少时间,欢迎大家积极参与! 活动已经截止了。。。
文章
姚 鑫 · 五月 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`命令不会将裸指示符回滚到事务开始时的值。
如果完整全局变量引用包含扩展全局变量引用,则后续的裸全局变量引用将采用相同的扩展全局引用;不必将扩展引用指定为裸全局引用的一部分。
公告
Claire Zheng · 三月 11, 2021
亲爱的社区开发者们,
我很高兴地向大家介绍一位我们的新版主@姚鑫
@姚鑫是东华医为的一名开发工程师。
以下是@姚鑫的自我介绍:
大家好,我非常热衷于与开发者们分享我的技术经验。作为一名移动端全栈开发工程师,我发表了《Caché 23种设计模式》《Caché 算法与数据结构》《Caché 从入门到精通》《疯狂 Caché》《Caché 命令大全》《Caché 函数大全》《Caché 变量大全》《Caché SQL 必知必会》等一系列文章集。
在CSDN(中国最大的开发者社区之一),我被认证为博客专家,CSDN优秀讲师。
在掘金网这个帮助开发者成长的知名社区,获得了2020年掘金十大年度人气作者称号。
我很荣幸能够加入InterSystems开发者社区(中文版)并参与到社区管理、运营中,希望可以同使用InterSystems技术的开发者更好地交流、共同成长。
感谢@姚鑫,恭喜你成为新版主! 感谢@姚鑫!期待更多大作! 欢迎新版主@姚鑫 欢迎新版主@姚鑫期待将来分享更多关于IRIS数据平台的经验
文章
Lele Yang · 六月 8, 2021
如果您在升级了系统之后,打开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
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` 与 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
在这篇文章中,我将解释如何通过使用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
问题
天恒 周 · 八月 6, 2022
cache的题目资源,类似于Oracle的OCP试题那种,能反应出对基础概念的掌握。 回答您的问题:
1. 我们海外在招募考试平台测试者,您可以直接给certification@intersystems.com 发邮件申请,具体内容可以参考:https://community.intersystems.com/post/beta-testers-needed-our-upcoming-intersystems-iris-system-administration-specialist;
2. 我们国内也即将推出初中高级的培训认证体系,敬请关注。
这还有网上的一些体验题目:https://community.intersystems.com/sites/default/files/post-associated-docs/sysadmin_practice_questions_0.pdf
谢谢您的关注! 好的,感谢!
问题
Johnny Wang · 七月 13, 2021
各位老师好!
如下两图,是HL7信息体,在形成消息之前,我们一般会先制定文档,包括消息题、消息段、阈值;但是最终在Ensemble中形成的消息是怎么一个过程? 制定好的消息文档可以转换成IRIS可以读取的格式,导入到IRIS中成为消息Schema结构。在处理消息时,可以配置接口应用我们指定的消息Schema结构去处理消息。更多细节可参见文档:HL7 Schemas and Available Tools | Routing HL7 Version 2 Messages in Productions | InterSystems IRIS for Health 2023.1
文章
Qiao Peng · 五月 25, 2022
%SYS.Journal.Record 类有一个查询(query), List, 可以列出Journal文件中记录的数据修改历史。例如,要查询谁对global节点^QP(1,2)做过修改,可以使用如下代码。它查询Journal文件(输入参数pFilePath)中的global节点(输入参数pSearchGlobal)的操作:
ClassMethod SearchGlobal(pSearchGlobal = "^QP(1,2)", pFilePath = "C:\InterSystems\IRISHealth\mgr\journal\20220525.003")
{
Set tRS = ##class(%ResultSet).%New("%SYS.Journal.Record:List")
Set tSC = tRS.Execute(pFilePath)
While (tRS.Next())
{
Set address = tRS.Data("Address")
Set globalNode = tRS.Data("GlobalNode")
Set newValue = tRS.Data("NewValue")
Set type = tRS.Data("TypeName")
Set processid = tRS.Data("ProcessID")
Set time = tRS.Data("TimeStamp")
Set globalRef = tRS.Data("GlobalReference")
If globalNode=pSearchGlobal
{
W !
W time,!
W processid,!
W address,!
W type," ",globalRef,"=",newValue,!
}
}
}
文章
Weiwei Gu · 九月 14, 2023
昨天,我在一个客户网站提供从 Studio 迁移到 VS Code 的定制咨询时,就遇到了这种情况。
该站点的服务器已配置为使用delegated authentication,但尚未针对 /api/atelier Web 应用程序设置“delegated”复选框,而 InterSystems ObjectScript 扩展包的成员正是使用该复选框进行连接的。
一旦我们的应用程序设置了其复选框并单击了服务器管理器刷新按钮,就可以在服务器上枚举命名空间。
公告
Claire Zheng · 十二月 22, 2022
2022年12月24日-25日,卫生健康信息标准应用管理培训班 (第二期)将于线上举办,此次培训班由国家卫生健康委统计信息中心指导、由《中国卫生信息管理杂志》社、深圳市卫生健康信息协会主办,InterSystems协办。详细日程请点击此处了解。您可以通过以下方式参与:
报名观看(可申请学分)
视频号(可观看直播)
如需要回看,请扫描“可申请学分”的二维码观看
公告
Claire Zheng · 三月 1, 2022
Hi开发者们,
是时候公布 InterSystems开发者Python竞赛的优胜者了!准备好了吗!
这些开发者和他们的应用程序赢得了雷鸣般的掌声:
🏆 专家提名奖(Experts Nomination)- 获奖者由我们特别挑选的专家团选出:
🥇 第一名,奖金 $4,000 获奖项目 django-iris ,开发者 @Dmitry.Maslennikov
🥈 第二名,奖金 $2,000 获奖项目 appmsw-sql2xlsx ,开发者 @MikhailenkoSergey
🥉 第三名,奖金 $1,000 获奖项目 iris-python-apps ,开发者 @Muhammad.Waseem
以下为更多优胜者:
🏅 奖金$100 ,获奖项目 iris-python-dashboards ,开发者@Evgeniy.Potapov
🏅 奖金$100 ,获奖项目 GlobalToJSON-ePython-pure ,开发者 @Robert.Cemper1003
🏅 奖金$100 ,获奖项目 blockchain - [ IRIS python ] ,开发者 @davimassaru.teixeiramuta
🏅 奖金$100 ,获奖项目 AI Image Object Detector ,开发者@Yuri.Gomes
🏅 奖金$100 ,获奖项目GlobalToJSON-embeddedPython ,开发者@Robert.Cemper1003
🏅 奖金$100 ,获奖项目 IRIS-Database-and-Machine-Learning-Based-Approaches-for-Prediction-of-Spontaneous-Intracerebral-Hemo ,开发者 @Fatian.Wu
🏅 奖金$100 ,获奖项目 DIMSE Iris Dicom Fhir Service ,开发者@Ron.Sweeney1582
🏅 奖金$100 ,获奖项目 Django-Interop ,开发者 @Fernando.VianaMaia
🏅 奖金$100 ,获奖项目 IRIS Text2Audio ,开发者 @Yuri.Gomes
🏆 社区提名奖(Community Nomination)- 获得总投票数最多的应用:
🥇 第一名,奖金 $1,000 ,获奖项目 django-iris ,开发者 @Dmitry.Maslennikov
🥈 第二名,奖金 $625 ,获奖项目 appmsw-sql2xlsx ,开发者 @MikhailenkoSergey
🥉 第三名,奖金 $625 ,获奖项目 IRIS-Database-and-Machine-Learning-Based-Approaches-for-Prediction-of-Spontaneous-Intracerebral-Hemo ,开发者 @Fatian.Wu
恭喜所有优胜者!
感谢大家对本次比赛的关注和付出!
公告
Qiao Peng · 三月 3, 2021
InterSystems API Manager (IAM) 版本1.5已正式发布。
IAM容器,包括从原有IAM版本升级的所有相关工件, 现在可以在 WRC 软件发布网址 组件区下载。
该版本的小版本号是 IAM 1.5.0.9-4。
InterSystems API Manager 1.5 使管理API通讯、与你的环境集成、加载API用户更加容易。它包含很多新特性,包括:
改进的用户体验
新的开发者门户工具
对Kafka connectivity的支持
这个版本基于Kong Enterprise version 1.5.0.9。之前的IAM版本包括一个贴牌版本的Kong Enterprise, 在本版本中的Kong Enterprise不再贴牌。 这个变化让我们可以更快的节奏带给您新的版本,并更有效地利用Kong提供的文档和其它资源。
请在 这里 查看IAM 1.5 的文档。这个文档仅说明IAM特殊的元素。产品中的文档链接直接打开Kong Enterprise的文档。
从IAM 0.34-1 升级需要通过3个中间版本累积升级,在 文档中有详细的说明。
IAM 仅以OCI (Open Container Initiative) 或 Docker 容器格式发放。容器镜像可运行在Linux x86-64 和 Linux ARM64的OCI 兼容的运行引擎上, 详情请参考 支持的平台。
Best Regards,
Stefan 欢迎开发者们多关注!