清除过滤器
公告
jieliang liu · 三月 30, 2022
大家好,欢迎来到2022年3月开发者社区更新!
我们最近在InterSystems社区对开发者们的体验做了一些改进:
全新的社区内容搜索功能
综合社区数据
链接你的脸书账号
帖子页面更新:标签、作者块、草稿突出显示
下面让我们仔细看看。
社区搜
我们已经在社区网站上部署了一个全新的搜索引擎。有两个搜索选项:
快速搜索
高级搜索
通过DC快速搜索,你可以很容易地找到一个帖子/标签/用户并直接进入该网页。
在建议的选项中没有找到合适的东西?
试着通过点击🔍按钮使用DC高级搜索:
在这里,你可以轻松地为你的搜索查询添加高级参数:
按特定用户的帖子搜索
通过特定标签搜索
按特定的帖子类型或只按你的帖子搜索
你还可以按时间段和相关性对结果进行排序:
综合社区数据
现在你可以看到InterSystems开发社区的数据统计了:
链接你的脸书账号
在你的DC资料中添加Facebook链接,以认识新朋友,拉近彼此的距离。
进入你的DC用户资料-->编辑-->其他信息-->Facebook资料
帖子页面更新:标签、作者块、草稿突出显示
你问了 - 我们做到了! 现在DC标签出现在帖子的正文中。
另外,在帖子页面,你现在可以在右边的块中看到作者的联系信息:
DC网站上的草稿现在是蓝色突出显示:
希望你喜欢我们的更新
在DC GitHub上提交您的改进请求和错误报告。或者在本帖的评论中发表您的建议。
请继续关注!
文章
Qiao Peng · 一月 10, 2021
# Swift-FHIR-Iris
iOS应用程序支持将HealthKit数据导入InterSystems IRIS医疗版(或任何FHIR资源仓库库)

# 目录
* [演示目的](#goal)
* [如何运行此演示](#rundemo)
* [先决条件](#prerequisites)
* [安装Xcode](#installxcode)
* [打开SwiftUi](#openswiftui)
* [配置模拟器](#simulator)
* [启动InterSystems FHIR服务器](#lunchfhir)
* [在iOS应用程序上操作](#iosplay)
* [工作原理](#howtos)
* [iOS](#howtosios)
* [如何检查健康数据的授权](#authorisation)
* [如何连接FHIR资源仓库](#howtoFhir)
* [如何将患者信息保存到FHIR资源仓库](#howtoPatientFhir)
* [如何从HealthKit中提取数据](#queryHK)
* [如何将HealthKit数据转换为FHIR](#HKtoFHIR)
* [后端 (FHIR)](#backend)
* [前端](#frontend)
* [ToDos](#todo)
# 演示目的
目的是创建FHIR协议的端到端演示。
这里的端到端指的是从一个信息源到另一个信息源,例如iPhone。
苹果HealthKit将收集到的健康数据转换为FHIR,再发送到InterSystems IRIS 医疗版存储库。
必须通过web接口访问这些信息。
**TL;DR**: iPhone -> InterSystems FHIR -> web界面.
# 如何运行此演示
## 先决条件
* 客户端 (iOS)
* Xcode 12
* 服务器和Web应用程序
* Docker
## 安装 Xcode
这里没有太多要说的,打开AppStore,搜索Xcode,安装。
## 打开SwiftUi project
Swift是苹果在iOS、Mac、Apple TV和Apple Watch中使用的一种编程语言,是objective-C的替代品。
双击Swift-FHIR-Iris.xcodeproj
单击左上角的箭头打开模拟器。

## 配置模拟器
打开Health
点击“Steps”
添加数据

## 启动InterSystems FHIR服务器
在该git的根目录下,运行以下命令:
```sh
docker-compose up -d
```
构建过程结束时,你将连接到FHIR资源仓库:
http://localhost:32783/fhir/portal/patientlist.html

该门户网站由@diashenrique创建.
为处理Apple活动足迹,进行了一些修改。
## 在iOS应用程序上操作
iOS应用程序首先会请求你同意分享部分信息。
点击授权

然后点击“Save and test server”对FHIR服务器进行测试
默认设置指向docker配置。
操作成功后,就可以输入患者信息。
名字、姓氏、生日、性别。
将患者信息保存到Fhir。弹出窗口将显示唯一的Fhir ID。

可在门户网站查阅该患者信息:
访问: http://localhost:32783/fhir/portal/patientlist.html
在这里我们可以看到,增加了一个新的病人“Toto”,0个活动。

发送她的活动信息:
回到iOS应用程序,点击“Step count”。
这里显示的是一周的步数。在我们的案例中有2条记录。
现在可以单击发送,将这些数据发送到InterSystems IRIS FHIR。

从门户网站上查询新的活动记录:
现在我们可以看到Toto有两条新的观察和活动消息。

你还可以单击“chart”按钮以图表格式显示。

# 工作原理
## iOS
该demo大部分是基于SwiftUI构建的。
https://developer.apple.com/xcode/swiftui/
iOS和co的最新框架。
### 如何检查健康数据的授权
它在SwiftFhirIrisManager 类中。
该类采用单例模式,可使用@EnvironmentObject对应用程序中进行的所有操作进行注释。
更多信息请访问 : https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views
调用requestAuthorization的方法如下:
```swift
// Request authorization to access HealthKit.
func requestAuthorization() {
// Requesting authorization.
/// - Tag: RequestAuthorization
let writeDataTypes: Set = dataTypesToWrite()
let readDataTypes: Set = dataTypesToRead()
// requset authorization
healthStore.requestAuthorization(toShare: writeDataTypes, read: readDataTypes) { (success, error) in
if !success {
// Handle the error here.
} else {
DispatchQueue.main.async {
self.authorizedHK = true
}
}
}
}
```
其中healthStore是HKHealthStore()的对象。
HKHealthStore类似于iOS中的healthdata数据库。
dataTypesToWrite和dataTypesToRead是我们想要在数据库中查询的对象。
授权的目的可以通过在Info.plist xml文件中添加以下内容完成:
```xml
NSHealthClinicalHealthRecordsShareUsageDescription
Read data for IrisExporter
NSHealthShareUsageDescription
Send data to IRIS
NSHealthUpdateUsageDescription
Write date for IrisExporter
```
### 如何连接FHIR资源仓库
对于这一部分,我使用了从Smart-On-FHIR网站下载的FHIR包 : https://github.com/smart-on-fhir/Swift-FHIR
使用的类是FHIROpenServer。.
```swift
private func test() {
progress = true
let url = URL(string: self.url)
swiftIrisManager.fhirServer = FHIROpenServer(baseURL : url! , auth: nil)
swiftIrisManager.fhirServer.getCapabilityStatement() { FHIRError in
progress = false
showingPopup = true
if FHIRError == nil {
showingSuccess = true
textSuccess = "Connected to the fhir repository"
} else {
textError = FHIRError?.description ?? "Unknow error"
showingSuccess = false
}
return
}
}
```
这一步将在单例swiftIrisManager中创建一个新的对象fhirServer。
接下来使用getCapabilityStatement()
如果能够检索到FHIR服务器的capabilityStatement,则意味着已成功连接到FHIR资源仓库。
这个资源仓库不在HTTPS下,默认情况下Apple会阻止这种通信。
想要获取HTTP支持,可以对Info.plist xml文件进行如下编辑:
```xml
NSAppTransportSecurity
NSExceptionDomains
localhost
NSIncludesSubdomains
NSExceptionAllowsInsecureHTTPLoads
```
### 如何将患者信息保存到FHIR资源仓库
基本操作:首先检查存储库中是否已经存在该患者的信息
```swift
Patient.search(["family": "\(self.lastName)"]).perform(fhirServer)
```
搜索具有相同姓氏的患者。
在这里,我们可以想象一下其他场景,比如使用Oauth2和JWT令牌加入patientId及其令牌。但在这个演示中,我们简单操作即可。
如果该患者信息已经存在,可以对其进行检索;否则,则创建新的患者信息 :
```swift
func createPatient(callback: @escaping (Patient?, Error?) -> Void) {
// Create the new patient resource
let patient = Patient.createPatient(given: firstName, family: lastName, dateOfBirth: birthDay, gender: gender)
patient?.create(fhirServer, callback: { (error) in
callback(patient, error)
})
}
```
### 如何从HealthKit中提取数据
通过查询healthkit商店 store(HKHealthStore())即可完成。
这里我们查询一下步数。
使用predicate做好查询准备。
```swift
//Last week
let startDate = swiftFhirIrisManager.startDate
//Now
let endDate = swiftFhirIrisManager.endDate
print("Collecting workouts between \(startDate) and \(endDate)")
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: HKQueryOptions.strictEndDate)
```
然后,会根据数据类型(HKQuantityType.quantityType(forIdentifier: .stepCount))和predicate内容进行查询。
```swift
func queryStepCount(){
//Last week
let startDate = swiftFhirIrisManager.startDate
//Now
let endDate = swiftFhirIrisManager.endDate
print("Collecting workouts between \(startDate) and \(endDate)")
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: HKQueryOptions.strictEndDate)
let query = HKSampleQuery(sampleType: HKQuantityType.quantityType(forIdentifier: .stepCount)!, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { (query, results, error) in
guard let results = results as? [HKQuantitySample] else {
return
}
process(results, type: .stepCount)
}
healthStore.execute(query)
}
```
### 如何将HealthKit数据转换为FHIR
在这部分,我们使用了微软软件包HealthKitToFHIR
https://github.com/microsoft/healthkit-to-fhir
这个包很有用,为开发商提供了将HKQuantitySample转换为FHIR Observation的功能。
```swift
let observation = try! ObservationFactory().observation(from: item)
let patientReference = try! Reference(json: ["reference" : "Patient/\(patientId)"])
observation.category = try! [CodeableConcept(json: [
"coding": [
[
"system": "http://terminology.hl7.org/CodeSystem/observation-category",
"code": "activity",
"display": "Activity"
]
]
])]
observation.subject = patientReference
observation.status = .final
print(observation)
observation.create(self.fhirServer,callback: { (error) in
if error != nil {
completion(error)
}
})
```
其中item是HKQuantitySample,在我们的例子中是stepCount类型。
这个factory完成了大部分工作,将“unit”和“type”转换为FHIR codeableConcept,并将“value”转换为FHIR valueQuantity。
对PatientId的引用是通过强制转换json fhir引用手动完成的。
```swift
let patientReference = try! Reference(json: ["reference" : "Patient/\(patientId)"])
```
对类别进行同样的操作 :
```swift
observation.category = try! [CodeableConcept(json: [
"coding": [
[
"system": "http://terminology.hl7.org/CodeSystem/observation-category",
"code": "activity",
"display": "Activity"
]
]
])]
```
最后,在fhir资源仓库中创建observation :
```swift
observation.create(self.fhirServer,callback: { (error) in
if error != nil {
completion(error)
}
})
```
## 后端 (FHIR)
没什么好说的,它基于InterSystems社区的fhir模板 :
https://openexchange.intersystems.com/package/iris-fhir-template
## 前端
基于Henrique作品,Henrique是使用jquery制作的FHIR资源仓库的一个很好的前端。
https://openexchange.intersystems.com/package/iris-fhir-portal
文章
Michael Lei · 八月 12, 2021
我最近看到一个客户问题,是使用 Caché 数据库上运行的病毒扫描程序导致应用程序间歇性变慢和用户响应时间不佳。
出乎意料的是,这是一个常见问题,所以本帖就是提个醒,要将主要 Caché 组件排除在病毒扫描之外。
通常,病毒扫描必须排除 CACHE.DAT 数据库文件和 Caché 二进制文件。 如果防病毒软件扫描 CACHE.DAT 和 InterSystems 文件,那么系统性能_将_受到较大影响。
具体来说,防病毒软件必须排除的 Caché 文件包括:
* Caché 数据库 (CACHE.DAT)。
* Ensemble/bin 或 cache/bin 目录中的 Caché 可执行文件。
* 写入映像日志 (WIJ)。
* 日志目录中的日志文件。
更多详细信息,请参见在线文档。
[更多 Caché 文档](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GSA_thirdparty)
文章
姚 鑫 · 二月 22, 2021
# 第四十四章 Caché 变量大全 $ZTRAP 变量
包含当前错误陷阱处理程序的名称。
# 大纲
```
$ZTRAP
$ZT
```
# 描述
`$ZTRAP`包含当前错误陷阱处理程序的行标签名和/或例程名。有三种方法可以设置`$ZTRAP`:
- `SET $ZTRAP=“location”`
- `SET $ZTRAP=“*location”`
- `SET $ZTRAP=“^%ET” or “^%ETN”`
在这里,位置可以指定为标签(当前例程中的行标签)、`^routine`(指定外部例程的开始)或`label^routine`(指定外部例程中的指定标签)。
**然而,`$ZTRAP=label^routine`不能用于程序块。过程块中的`$ZTRAP`不能用于转到过程体之外的位置;过程块中的`$ZTRAP`只能引用该过程块中的一个位置**。
## Location
使用设置命令,可以将位置指定为带引号的字符串。
- 在例程中,可以将位置指定为标签(当前例程中的行标签)、`^routine`(指定外部例程的开始)或`label^routine`(指定外部例程中的指定标签)。不要在引用过程或过程中的标签的例程中指定位置。这是一个无效位置;当InterSystems IRIS试图执行`$ZTRAP`时,会导致运行时错误。
- 在过程中,可以将位置指定为标签;过程块中私有标签。过程块中的`$ZTRAP`不能用于转到过程体之外的位置;过程块中的`$ZTRAP`只能引用该过程块中的一个位置。因此,在过程中,不能将`$ZTRAP`设置为`^routine`或`label^routine`.尝试这样做将导致``错误。
在过程中,将`$ZTRAP`设置为私有标签名,但是`$ZTRAP`值不是私有标签名;它是从过程标签(过程的顶部)到私有标签的行位置的偏移量。例如,`+17^myproc`.
注意:`$ZTRAP`在某些情况下(而不是在过程中)为`label + offset`提供传统支持。这个可选的`+ offset`是一个整数,指定要从`label`偏移的行数。标签必须在相同的例程中。不建议使用`+offset`,它可能会导致编译警告错误。 InterSystems建议您在指定位置时避免使用行偏移量。
调用过程或IRIS `SYS`%例程时,不能指定`+`偏移量。如果尝试这样做,则InterSystems IRIS会发出错误。
`$ZTRAP`位置必须在当前名称空间中。 `$ZTRAP`不支持扩展的例程引用。
如果指定了不存在的行标签(当前例程中不存在的位置),则会发生以下情况:
- 显示`$ZTRAP`:在例程中,`$ZTRAP`包含`label ^ routine`。例如,`DummyLabel^MyRou`。在一个过程中,`$TRAP`包含最大可能的偏移量:`+ 34463 ^ MyProc`。
- 调用$ZTRAP:InterSystems IRIS发出``错误消息。
每个堆栈级别可以有其自己的`$ZTRAP`值。设置`$ZTRAP`时,系统会将`$ZTRAP`的值保存为先前的堆栈级别。当前堆栈级别结束时,InterSystems IRIS会恢复该值。要在当前堆栈级别启用错误陷阱,请通过指定`$ZTRAP`的位置将其设置为错误陷阱处理程序。例如:
```java
/// d ##class(PHA.TEST.SpecialVariables).ZTRAP()
ClassMethod ZTRAP()
{
IF $ZTRAP="" {
WRITE !,"$ZTRAP not set"
} ELSE {
WRITE !,"$ZTRAP already set: ",$ZTRAP
SET oldtrap=$ZTRAP
}
SET $ZTRAP="Etrap1^Handler"
WRITE !,"$ZTRAP set to: ",$ZTRAP
// program code
SET $ZTRAP=oldtrap
WRITE !,"$ZTRAP restored to: ",$ZTRAP
}
```
发生错误时,此格式将展开调用堆栈,并将控制权转移到指定的错误陷阱处理程序。
在SqlComputeCode中,不要设置`$ZTRAP = $ZTRAP`。这可能导致事务处理和错误报告方面的重大问题。
要禁用错误捕获,请将`$ZTRAP`设置为空字符串(`“”`)。这将清除在当前DO堆栈级别设置的所有错误陷阱。
注意:在“终端”提示符下使用$ZTRAP仅限于当前代码行。 `SET $ZTRAP`命令和生成错误的命令必须在同一行代码中。终端在每个命令行的开头将`$ZTRAP`还原为系统默认值。
## *Location
在例程中,可以选择在发生错误后保留调用堆栈。为此,请在位置之前和双引号内放置一个星号(`*`)。该表格不适用于程序。尝试这样做会导致`` 错误。只能在不是过程的子例程中使用此示例中的:
```java
/// d ##class(PHA.TEST.SpecialVariables).ZTRAP()
ClassMethod ZTRAP()
{
Main
SET $ZTRAP="*OnError"
WRITE !,"$ZTRAP set to: ",$ZTRAP
// program code
OnError
// Error handling code
QUIT
}
```
这种格式只会导致转到`$ZTRAP`中指定的行标签;`$STACK`和`$ESTACK`保持不变。`$ZTRAP`错误处理例程的上下文框架与发生错误的上下文框架相同。但是,InterSystems IRIS会将`$ROLES`重置为设置`$ZTRAP`的执行级别的有效值;这会阻止`$ZTRAP`错误处理程序使用在建立错误处理程序后授予例程的提升权限。完成`$ZTRAP`错误处理例程后,InterSystems IRIS将堆栈展开到上一个上下文级。这种形式的`$ZTRAP`对于分析意外错误特别有用。
请注意,星号设置`$ZTRAP`选项;它不是位置的一部分。因此,在`$ZTRAP`上执行`WRITE`或`ZZDUMP`时不会显示此星号。
## ^%ETN
在例程中,`set $ZTRAP=“^%ETN”`将系统提供的错误例程`%ETN`建立为当前错误捕获处理程序。`%ETN`在调用它的发生错误的上下文中执行。(`%et`是`%etn`的旧名称。它们的功能相同,但`%ETN`的效率略高一些。)。`^%ETN`错误处理程序的行为总是前缀星号(`*`)。
因为过程块中的`$ZTRAP`不能用于转到过程主体之外的位置,所以不能在过程中使用`SET $ZTRAP=“^%ETN”`。尝试这样做会导致``错误。
## TRY / CATCH 与 $ZTRAP
不能在`TRY`块内设置`$ZTRAP`。尝试这样做会生成编译错误。可以在`TRY`块之前或在`CATCH`块内设置`$ZTRAP`。
**无论之前是否设置了`$ZTRAP`,`TRY`块中发生的错误都由`CATCH`块处理。`CATCH`块内发生的错误由当前错误捕获处理程序处理。**
下面的第一个示例显示了`TRY`块中发生的错误。下面的第二个示例显示了`try`块中引发的异常。在这两种情况下,都会采用`CATCH`块,而不是`$ZTRAP`:
```java
/// d ##class(PHA.TEST.SpecialVariables).ZTRAP()
ClassMethod ZTRAP()
{
SET $ZTRAP="Ztrap"
TRY { WRITE 1/0 } /* divide-by-zero error */
CATCH { WRITE "Catch taken" }
QUIT
Ztrap
WRITE "$ZTRAP taken"
SET $ZTRAP=""
QUIT
}
```
```java
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP()
Catch taken
```
```java
/// d ##class(PHA.TEST.SpecialVariables).ZTRAP1()
ClassMethod ZTRAP1()
{
SET $ZTRAP="Ztrap"
TRY {
SET myvar=##class(Sample.MyException).%New("Example Error",999,,errdatazero)
WRITE !,"Throwing an exception!",!
THROW myvar
QUIT
} CATCH {
WRITE "Catch taken"
}
QUIT
Ztrap
WRITE "$ZTRAP taken"
SET $ZTRAP=""
QUIT
}
```
```java
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP1()
Catch taken
```
但是,`try`块可以调用设置和使用`$ZTRAP`的代码。在下面的示例中,`$ZTRAP`而不是`CATCH`块捕获被零除错误:
```java
/// d ##class(PHA.TEST.SpecialVariables).ZTRAP2()
ClassMethod ZTRAP2()
{
TRY { DO Errsub }
CATCH { WRITE "Catch taken" }
QUIT
Errsub
SET $ZTRAP="Ztrap"
WRITE 1/0 /* divide-by-zero error */
QUIT
Ztrap
WRITE "$ZTRAP taken"
SET $ZTRAP=""
QUIT
}
```
```java
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP2()
$ZTRAP taken
```
CATCH块中的`Throw`命令还可以调用`$ZTRAP`错误处理程序。
# 示例
下面的示例将`$ZTRAP`设置为此程序中的`OnError`例程。然后,它调用发生错误的`Suba`(尝试将数字除以0)。当错误发生时,InterSystems IRIS调用`$ZTRAP`中指定的`OnError`例程。`OnError`在设置`$ZTRAP`的上下文级别调用。因为`OnError`与`Main`处于相同的上下文级别,所以执行不会返回`Main`。
```java
/// d ##class(PHA.TEST.SpecialVariables).ZTRAP3()
ClassMethod ZTRAP3()
{
Main
NEW $ESTACK
SET $ZTRAP="OnError"
WRITE !,"$ZTRAP set to: ",$ZTRAP
WRITE !,"Main $ESTACK= ",$ESTACK // 0
WRITE !,"Main $ECODE= ",$ECODE
DO SubA
WRITE !,"Returned from SubA" // not executed
WRITE !,"MainReturn $ECODE= ",$ECODE
QUIT
SubA
WRITE !,"SubA $ESTACK= ",$ESTACK // 1
WRITE !,6/0 // Error: division by zero
WRITE !,"fine with me"
QUIT
OnError
WRITE !,"OnError $ESTACK= ",$ESTACK // 0
WRITE !,"$ECODE= ",$ECODE
QUIT
}
```
```java
DHC-APP>d ##class(PHA.TEST.SpecialVariables).ZTRAP3()
$ZTRAP set to: +970^PHA.TEST.SpecialVariables.1
Main $ESTACK= 0
Main $ECODE= ,ZSYNTAX,ZSYNTAX,ZSYNTAX,ZMETHOD DOES NOT EXIST,M9,M6,M9,
SubA $ESTACK= 1
OnError $ESTACK= 0
$ECODE= ,ZSYNTAX,ZSYNTAX,ZSYNTAX,ZMETHOD DOES NOT EXIST,M9,M6,M9,M9,
```
下面的示例与前面的示例相同,但有一个例外:`$ZTRAP`位置前面有一个星号(`*`)。当错误发生在`SUBA`中时,此星号会导致InterSystems IRIS在`SUBA`(发生错误的地方)的上下文级调用`OnError`例程,而不是在`Main`(设置`$ZTRAP`的地方)的上下文级调用`OnError`例程。因此,当`OnError`完成时,执行将在`do`命令之后的行返回到`Main`。
```java
/// d ##class(PHA.TEST.SpecialVariables).ZTRAP4()
ClassMethod ZTRAP4()
{
Main
NEW $ESTACK
SET $ZTRAP="*OnError"
WRITE !,"$ZTRAP set to: ",$ZTRAP
WRITE !,"Main $ESTACK= ",$ESTACK // 0
WRITE !,"Main $ECODE= ",$ECODE
DO SubA
WRITE !,"Returned from SubA" // executed
WRITE !,"MainReturn $ECODE= ",$ECODE
QUIT
SubA
WRITE !,"SubA $ESTACK= ",$ESTACK // 1
WRITE !,6/0 // Error: division by zero
WRITE !,"fine with me"
QUIT
OnError
WRITE !,"OnError $ESTACK= ",$ESTACK // 1
WRITE !,"$ECODE= ",$ECODE
QUIT
}
```
文章
姚 鑫 · 三月 15, 2021
# 第十章 SQL排序(二)
# 查询排序
InterSystems SQL提供了排序规则功能,可用于更改字段的排序规则或显示。
# 第十章 SQL排序(二)
# 查询排序
InterSystems SQL提供了排序规则功能,可用于更改字段的排序规则或显示。
## 查询明细排序
将排序功能应用于查询选择项会更改该项目的显示。
- 字母大小写:默认情况下,查询显示带有大写和小写字母的字符串。例外情况是对排序规则类型`SQLUPPER`的字段进行`DISTINCT`或`GROUP BY`操作。这些操作以所有大写字母显示该字段。可以使用`%EXACT`排序功能来反转此字母大小写转换,并以大写和小写字母显示该字段。不应在选择项列表中使用`%SQLUPPER`排序规则函数以所有大写字母显示字段。**这是因为`%SQLUPPER`在字符串的长度上添加了一个空格字符。请改用`UPPER`函数:**
```SQL
SELECT TOP 5 Name,$LENGTH(Name) AS NLen,
%SQLUPPER(Name) AS UpCollN,$LENGTH(%SQLUPPER(Name)) AS UpCollLen,
UPPER(Name) AS UpN,$LENGTH(UPPER(Name)) AS UpLen
FROM Sample.Person
```

- 字符串截断:可以使用`%TRUNCATE`排序函数来限制显示的字符串数据的长度。 `%TRUNCATE`比`%SQLUPPER`更可取,后者会在字符串的长度上添加一个空格字符。
```SQL
SELECT TOP 5 Name,$LENGTH(Name) AS NLen,
%TRUNCATE(Name,8) AS TruncN,$LENGTH(%TRUNCATE(Name,8)) AS TruncLen
FROM Sample.Person
```

请注意,不能嵌套排序规则函数或大小写转换函数。
- `WHERE`子句比较:大多数`WHERE`子句谓词条件比较使用字段/属性的排序规则类型。因为字符串字段默认为`SQLUPPER`,所以这些比较通常不区分大小写。可以使用`%EXACT`排序规则功能使它们区分大小写:
-
下面的示例返回`Home_City`字符串匹配项,无论字母大小写如何:
```SQL
SELECT Home_City FROM Sample.Person WHERE Home_City = 'albany'
```

以下示例返回区分大小写的`Home_City`字符串匹配:
```SQL
SELECT Home_City FROM Sample.Person WHERE %EXACT(Home_City) = 'albany'
```

`SQL Follows`运算符(`]`)使用字段/属性归类类型。
但是,无论字段/属性的排序规则类型如何,SQL `Contains`运算符(`[`)都使用EXACT排序规则:
```SQL
SELECT Home_City FROM Sample.Person WHERE Home_City [ 'c'
ORDER BY Home_City
```

`%MATCHES`和`%PATTERN`谓词条件使用EXACT排序规则,而不管字段/属性的排序规则类型如何。 `%PATTERN`谓词提供区分大小写的通配符和不区分大小写的通配符(`'A'`)。
`ORDER BY`子句:`ORDER BY`子句使用名称空间默认排序规则对字符串值进行排序。因此,`ORDER BY`不会基于字母大小写进行排序。可以使用`%EXACT`排序规则根据字母大小写对字符串进行排序。
## `DISTINCT`和`GROUP BY`排序规则
默认情况下,这些操作使用当前的名称空间排序。默认的名称空间排序规则是`SQLUPPER`。
- `DISTINCT`:`DISTINCT`关键字使用名称空间默认排序规则来消除重复值。因此,`DISTINCT Name`返回所有大写字母的值。可以使用`EXACT`排序规则返回大小写混合的值。 `DISTINCT`消除仅字母大小写不同的重复项。**要保留大小写不同的重复项,但要消除确切的重复项,请使用`EXACT`排序规则。** 以下示例消除了精确的重复项(但不消除字母大写的变体),并以混合的大写和小写形式返回所有值:
```SQL
SELECT DISTINCT %EXACT(Name) FROM Sample.Person
```

`UNION`涉及隐式`DISTINCT`操作。
- `GROUP BY`:`GROUP BY`子句使用名称空间默认排序规则来消除重复的值。因此,`GROUP BY Name`返回所有大写字母的值。**可以使用`EXACT`排序规则返回大小写混合的值。** `GROUP BY`消除仅字母大小写不同的重复项。若要保留大小写不同的重复项,但要消除完全相同的重复项,必须在`GROUP BY`子句(而不是`select-item`)上指定`%EXACT`归类函数。
下面的示例返回大小写混合的值; `GROUP BY`消除重复项,包括字母大小写不同的重复项:
```SQL
SELECT %EXACT(Name) FROM Sample.Person GROUP BY Name
```

下面的示例返回大小写混合的值; `GROUP BY`消除了精确的重复项(但不消除字母大写的变体):
```SQL
SELECT Name FROM Sample.Person GROUP BY %EXACT(Name)
```

# 旧版排序类型
InterSystems SQL支持多种旧式排序规则类型。它们已被弃用,不建议与新代码一起使用,因为它们的目的是为遗留系统提供持续的支持。他们是:
- **`%ALPHAUP` — 除去问号(`“?”`)和逗号(`“,”`)之外的所有标点符号,并将所有小写字母转换为大写字母。主要用于映射旧全局变量。由`SQLUPPER`代替。**
- **`%STRING` —将逻辑值转换为大写,去除所有标点符号和空格(逗号除外),并在字符串的开头添加一个前导空格。它将所有仅包含空格(空格,制表符等)的值作为SQL空字符串进行整理。由`SQLUPPER`代替。**
- **`%UPPER` —将所有小写字母转换为大写字母。主要用于映射旧全局变量。由`SQLUPPER`代替。**
- `SPACE` — `SPACE`排序将单个前导空格附加到一个值,强制将其作为字符串求值。要建立`SPACE`排序规则,`CREATE TABL`E提供一个`SPACE`排序规则关键字,而ObjectScript在`%SYSTEM.Util`类的`Collation()`方法中提供一个`SPACE`选项。没有相应的SQL排序规则功能。
**注意:如果使用`EXACT`,`UPPER`或`ALPHAUP`排序定义了字符串数据类型字段,并且查询在此字段上应用了`%STARTSWITH`条件,则可能导致不一致的行为。如果指定给`%STARTSWITH`的子字符串是规范数字(尤其是负数和/或小数),则`%STARTSWITH`可能会根据字段是否被索引而给出不同的结果。如果未对列进行索引,则`%STARTSWITH`应该会按预期执行。如果该列已建立索引,则可能会发生意外的结果。**
# SQL和NLS排序
上面描述的SQL排序规则不应与InterSystems IRIS NLS排序规则功能混淆,后者提供符合特定本国语言排序规则要求的下标级别编码。这是提供分页的两个独立系统,它们在产品的不同级别上工作。
InterSystems IRIS NLS排序可以具有当前过程的过程级别排序,并且可以具有特定全局变量的不同排序。
为了确保使用InterSystems SQL时的正常运行,要求进程级NLS排序规则与所涉及的所有全局变量的NLS排序规则完全匹配,包括表所使用的全局变量以及用于临时文件(例如进程专用全局变量和IRIS TEMP)的全局变量。否则,查询处理器设计的不同处理计划可能会得出不同的结果。在发生排序的情况下,例如`ORDER BY`子句或范围条件,查询处理器将选择最有效的排序策略。它可以使用索引,可以在进程专用的全局文件中使用临时文件,可以在本地数组中排序,也可以使用`“]]”`(之后排序)比较。所有这些都是下标类型的比较,遵循有效的InterSystems IRIS NLS归类,这就是为什么所有这些类型的全局变量都必须使用完全相同的NLS归类的原因。
系统使用数据库默认排序规则创建全局变量。可以使用`%Library.GlobalEdit`类的`Create()`方法来创建具有不同排序规则的全局变量。唯一的要求是指定的归类可以是内置的(例如InterSystems IRIS标准),也可以是当前语言环境中可用的国家归类之一。
文章
姚 鑫 · 五月 23, 2021
# 第四章 收发电子邮件
本主题描述如何使用InterSystems IRIS发送和接收`MIME`电子邮件消息。
注意:本主题中的示例是经过组织的,因此管理电子邮件的方法可以用于不同的电子邮件服务器,这在测试和演示期间非常有用。这不一定是最适合生产需要的代码组织。
# 支持电子邮件协议
电子邮件使用标准协议通过Internet发送消息。
InterSystems IRIS支持以下三种协议:
- InterSystems IRIS提供`MIME`电子邮件的对象表示形式。它支持文本和非文本附件、单部分或多部分邮件正文,以及`ASCII`和非`ASCII`字符集的标题。
- 可以通过`SMTP`服务器发送电子邮件。`SMTP`(简单邮件传输协议)是发送电子邮件的Internet标准。
- 还可以通过`POP3`从电子邮件服务器检索电子邮件,`POP3`是从远程服务器检索电子邮件的最常用标准。
注意:InterSystems IRIS不提供邮件服务器。相反,它提供了连接到邮件服务器并与之交互的功能。
# InterSystems IRIS如何表示`MIME`电子邮件
首先,了解InterSystems IRIS如何表示`MIME`电子邮件非常有用。
通常,多部分`MIME`邮件由以下部分组成:
- 一组邮件标头,每个标头都包含邮件发送到的地址等信息。这还包括整个消息的`Mime-Type`标头和`Content-Type`标头。
对于多部分消息,`Content-Type`头必须是多部分/混合或多部分的其他子类型;`MIME`标准有许多变体。
- 多个消息部分,每个消息部分由以下部分组成:
- 一组内容标头,包括`Content-Type`标头和特定于此部件的其他标头。
- 一种正文,它可以是文本或二进制,并且可以使用与其它部分的正文不同的字符集。
InterSystems IRIS使用两个类来表示电子邮件:`%Net.MailMessage`和`%Net.MailMessagePart`,即`%Net.MailMessage`的超类。下图显示了这些类之间的关系:

- 要表示普通的、由一部分组成的消息,请使用`%Net.MailMessage`
- 要表示多部分消息,请使用`%Net.MailMessage`作为父消息,并使用`%Net.MailMessagePart`的多个实例作为其部分。
# 创建由单个部分组成的电子邮件
要创建由单个部分组成的电子邮件,请使用`%Net.MailMessage`类。要创建邮件,请执行以下操作:
1. 创建`%Net.MailMessage`的实例。
提示:可以将字符集指定为`%New()`;的参数,如果这样做,则会设置消息的`CharSet`属性。
2. 设置实例的`To`、`From`和`Subject`属性。
- `To`收件人-此邮件将发送到的电子邮件地址列表。此属性是标准的InterSystems IRIS列表类;要使用它,需要使用标准列表方法:`Insert()`、`GetAt()`、`RemoveAt()`、`Count()`和`Clear()`。
- `From`发件人-此邮件的发件人电子邮件地址。
- `Subject`主题-邮件的主题(如果您使用的SMTP服务器需要该主题)。
3. 可以选择设置日期、抄送、密件抄送和其他属性。
4. 如果邮件不是纯文本,请设置以下属性以指示您要创建的邮件的类型:
- 如果这是一封HTML邮件,请将`IsHTML`属性设置为1。
- 如果这是二进制消息,请将`IsBinary`属性设置为1。
5. 若要指定消息及其标头的字符集,请根据需要设置`CharSet`属性。
重要提示:在添加消息内容之前指定字符集非常重要。
6. 添加消息内容:
- 对于纯文本或`HTML`,请使用`TextData`属性,该属性是`%FileCharacterStream`的实例。不需要指定此流的`TranslateTable`属性;当指定邮件的字符集时,该属性会自动发生。
- 对于二进制数据,请使用`BinaryData`属性,该属性是`%FileBinaryStream`的实例。
提示:指定流的`Filename`属性时,请确保使用用户有权写入的目录。
要使用这些属性,请使用标准流方法:`Write()`、`WriteLine()`、`Read()`、`ReadLine()`、`Rewind()`、`MoveToEnd()`和`Clear()`。还可以使用流的`Size`属性,该属性提供消息内容的大小。
注意:应该了解正在使用的`SMTP`服务器的要求。例如,某些`SMTP`服务器要求包含主题标头。同样,某些`SMTP`服务器不允许任意`FROM`标头。
类似地,一些`SMTP`服务器识别优先级报头,而其他服务器则识别`X-Priority`。
示例1:`CreateTextMessage()`
以下方法创建一条简单消息并为其指定地址:
```java
ClassMethod CreateTextMessage() As %Net.MailMessage
{
Set msg = ##class(%Net.MailMessage).%New()
set msg.From = "test@test.com"
Do msg.To.Insert("xxx@xxx.com")
Do msg.Cc.Insert("yyy@yyy.com")
Do msg.Bcc.Insert("zzz@zzz.com")
Set msg.Subject="subject line here"
Set msg.IsBinary=0
Set msg.IsHTML=0
Do msg.TextData.Write("This is the message.")
Quit msg
}
```
示例2:`SimpleMessage()`
在实际发送邮件时指定地。上例的以下变体生成一条没有地址的文本消息:
```java
ClassMethod SimpleMessage() As %Net.MailMessage
{
Set msg = ##class(%Net.MailMessage).%New()
Set msg.Subject="Simple message "_$h
Set msg.IsBinary=0
Set msg.IsHTML=0
Do msg.TextData.Write("This is the message.")
Quit msg
}
```
`Samples`命名空间中还有其他示例。要查找它们,请在该命名空间中搜索`%Net.MailMessage`。
# 创建多部分电子邮件
要创建由多部分组成的电子邮件,请执行以下操作:
1. 创建`%Net.MailMessage`的实例,并将其`To`、`From`和`Subject`属性设置为。可以选择设置其他属性以指定其他邮件标头。
2. 将`IsMultiPart`属性设置为1。
3. 将`MultiPartType`属性设置为以下值之一: `"related"`, `"alternative"`, 或 `"mixed"`。这会影响整个消息的`Content-Type`标头。
4. 对于邮件应包含的每个部分,创建`%Net.MailMessagePart`的实例并指定其属性,如从步骤4开始的“创建由单个部分组成的电子邮件”中所述。
5. 对于父电子邮件,设置`Parts`属性,该属性是一个数组。将每个子消息部分插入到此数组中。
发送邮件时,`%Net.SMTP`类会根据需要自动设置邮件的`Content-Type`标头(给定`MultiPartType`属性值)。
# 指定电子邮件标题
如前所述,消息本身和消息的每个部分都有一组标头。
`%Net.MailMessage`和`%Net.MailMessagePart`类提供的属性使可以轻松访问最常用的标头,但可以添加所需的任何标头。本节提供有关所有标头以及如何创建自定义标头的信息。
给定消息部分的标头使用由该部分的`CharSet`属性指定的字符集。
注意:应该了解正在使用的`SMTP`服务器的要求。例如,某些`SMTP`服务器要求包含主题标头。同样,某些`SMTP`服务器不允许任意`FROM`标头。
类似地,一些`SMTP`服务器识别优先级报头,而其他服务器则识别`X-Priority`。
# 指定基本电子邮件标题
设置以下属性(仅在`%Net.MailMessage`中)以设置邮件本身最常用的标头:
- `To`-(必填)此邮件将发送到的电子邮件地址列表。此属性是标准的InterSystems IRIS列表;要使用它,请使用标准列表方法:`Insert()`、`GetAt()`、`RemoveAt()`、`Count()`和`Clear()`。
- From-(必填)发送此邮件的电子邮件地址。
- Date-此消息的日期。
- Subject-(必选)包含此邮件主题的字符串。
- Sender-邮件的实际发件人。
- Cc-此邮件将发送到的抄送地址列表。
- Bcc-此邮件将被发送到的密件副本地址列表。
## 内容类型标题
发送邮件时,邮件和每个邮件部分的`Content-Type`标头会自动设置如下:
- 如果消息是纯文本(`IsHTML`等于0,`IsBinary`等于0),则`Content-Type`标头被设置为 `"text/plain`。
- 如果消息是`HTML`(`IsHTML`等于1,`IsBinary`等于0),则`Content-Type`标头设置为`“text/html”`。
- 如果消息是二进制的(`IsBinary`等于1),则`Content-Type`报头设置为如果消息是二进制的(`IsBinary`等于1),则`Content-Type`报头设置为`"application/octet-stream"`.
- 如果邮件是多部分邮件,则会为`MultiPartType`属性的值适当设置`Content-Type`标头。
`%Net.MailMessage`和`%Net.MailMessagePart`都提供了`contentType`属性,使可以访问`Content-Type`标头。
## 内容传输编码标头
`%Net.MailMessage`和`%Net.MailMessagePart`都提供了`ContentTransferEncoding`属性,该属性提供了一种指定消息或消息部分的`Content-Transfer-Encoding`头的简单方法。
此属性可以是以下属性之一:`"base64" "quoted-printable" "7bit" "8bit"`
默认值如下:
对于二进制消息或消息部分:`"base64"`
**重要提示:请注意,如果内容为`“Base64”`编码,则不能包含任何Unicode字符。如果要发送的内容包括Unicode字符,请确保使用`$ZCONVERT`将内容转换为`UTF-8`,然后对其进行`base-64`编码。例如:**
```java
set BinaryText=$ZCONVERT(UnicodeText,"O","UTF8")
set Base64Encoded=$system.Encryption.Base64Encode(BinaryText)
```
收件人必须使用相反的过程来解码文本:
```java
set BinaryText=$system.Encryption.Base64Decode(Base64Encoded)
set UnicodeText=$ZCONVERT(BinaryText,"I","UTF8")
```
对于文本消息或消息部分:`"quoted-printable"`
## 自定义标题
使用`%Net.MailMessage`和`%Net.MailMessagePart`,可以通过访问`Headers`属性设置或获取自定义标题,该属性是一个具有以下结构的数组:
数组键 |数组值
---|---
标头的名称,如`“Priority”` | 标头的值
此属性用于包含其他标头,如`X-Priority`和其他标头。例如:
```java
do msg.Headers.SetAt(1,"X-Priority")
do msg.Headers.SetAt("High","X-MSMail-Priority")
do msg.Headers.SetAt("High","Importance")
```
不同的电子邮件服务器和客户端可以识别不同的标头,因此设置多个相似的标头以确保服务器或客户端接收到的邮件具有它可以识别的标头是很有用的。
文章
姚 鑫 · 五月 3, 2021
# 第二章 全局变量结构(一)
本章描述全局变量的逻辑视图,并概述全局变量是如何在磁盘上物理存储的。
# 全局变量的逻辑结构
全局变量是存储在物理InterSystems IRIS®数据库中的命名多维数组。
在应用程序中,全局变量到物理数据库的映射基于当前名称空间——名称空间提供一个或多个物理数据库的逻辑统一视图。
## 全局命名约定和限制
全局名称指定其目标和用途。有两种类型的全局变量和一组单独的变量,称为“进程私有全局变量”:
- 全局变量 - 这就是所谓的标准全局变量;通常,这些变量被简称为全局变量。它是驻留在当前命名空间中的永久性多维数组。
- **扩展全局引用-这是位于当前命名空间以外的命名空间中的全局引用。**
- **进程私有全局变量-这是一个数组变量,只有创建它的进程才能访问。**
全局变量的命名约定如下:
- 全局变量名称以脱字符(`^`)前缀开头。这个插入符号区分全局变量和局部变量。
- 全局变量名称中脱字符(`^`)前缀后的第一个字符可以是:
- 字母或百分号字符(%)-仅适用于标准全局变量。对于全局变量名称,字母被定义为`ASCII 65`到`ASCII 255`范围内的字母字符。如果全局名称以`“%”`开头(但不是`“%Z”`或`“%z”`),则此全局名称供InterSystems IRIS系统使用。`%GLOBAL`通常存储在IRISSYS或IRISLIB数据库中。
- 竖线(`|`)或左方括号(`[`)-表示扩展全局引用或进程专用全局变量。使用取决于后续字符。
- 全局变量名称的其他字符可以是字母、数字或句号(`.`)字符。
百分比(`%`)字符不能使用,除非作为全局名称的第一个字符。
`“.”`字符不能作为全局名称的最后一个字符。
- **全局名称最长可达31个字符(不包括脱字符前缀)。可以指定更长的全局名称,但InterSystems IRIS只将前31个字符视为重要字符。**
- 全局名称区分大小写。
- InterSystems IRIS对全局引用的总长度施加限制,而该限制又对任何下标值的长度施加限制。
**在IRISSYS数据库中,InterSystems将除以`“z”`、`“Z”`、`“%z”`和`“%Z”`开头的所有全局变量名称保留给自己。在所有其他数据库中,InterSystems保留所有以`“ISC”`开头的全局名称。和`“%isc.”`。**
## 示例全局名称及其用法
以下是各种全局名称的示例以及每种名称的用法:
- `^globalname` - 标准全局变量
- `^|"environment"|globalname` - 扩展全局变量引用的环境语法
- `^||globalname` - 进程私有全局变量
- `^|"^"|` - 进程私有全局变量
- `^[namespace]globalname` - 扩展全局变量引用中显式命名空间的括号语法
- `^[directory,system]globalname` - 扩展全局变量引用中隐含命名空间的括号语法
- `^["^"]globalname` - 进程私有全局变量
- `^["^",""]globalname` - 进程私有全局变量
注意:全局名称只能包含有效的标识符字符;默认情况下,这些字符如上所述。但是,NLS(国家语言支持)定义了一组不同的有效标识符字符集。全局名称不能包含`Unicode`字符。
因此,以下都是有效的全局名称:
```java
SET ^a="The quick "
SET ^A="brown fox "
SET ^A7="jumped over "
SET ^A.7="the lazy "
SET ^A1B2C3="dog's back."
WRITE ^a,^A,^A7,!,^A.7,^A1B2C3
KILL ^a,^A,^A7,^A.7,^A1B2C3 // keeps the database clean
```
## 全局节点和下标简介
全局通常有多个节点,通常由一个下标或一组下标标识。下面是一个基本示例:
```java
set ^Demo(1)="Cleopatra"
```
此语句引用全局节点`^Demo(1)`,它是`^Demo`全局节点中的一个节点。此节点由一个下标标识。
再举一个例子:
```java
set ^Demo("subscript1","subscript2","subscript3")=12
```
该语句指的是全局节点`^Demo("subscript1","subscript2","subscript3")`,它是同一全局中的另一个节点。此节点由三个下标标识。
再举一个例子:
```java
set ^Demo="hello world"
```
该语句引用不使用任何下标的全局节点`^Demo`。
全局的节点形成分层结构。ObjectScript提供了利用此结构的命令。例如,可以删除节点或删除节点及其所有子节点。
## 全局变量下标
下标有以下规则:
- 下标数值区分大小写。
- **下标值可以是任何ObjectScript表达式,前提是该表达式的计算结果不是空字符串(`""`)。**
**该值可以包括所有类型的字符,包括空格、非打印字符和Unicode字符。(请注意,非打印字符在下标数值中不太实用。)**
- 在解析全局引用之前,InterSystems IRIS计算每个下标的方式与计算任何其他表达式的方式相同。在下面的示例中,我们设置了`^Demo`全局的一个节点,然后以几种等效的方式引用该节点:
```java
DHC-APP>s ^Demo(1+2+3)="a value"
DHC-APP>w ^Demo(3+3)
a value
DHC-APP>w ^Demo(03+03)
a value
DHC-APP>w ^Demo(03.0+03.0)
a value
DHC-APP>set x=6
DHC-APP>w ^Demo(x)
a value
```
- InterSystems IRIS对全局引用的总长度施加限制,而该限制又对任何下标值的长度施加限制。
**注意:上述规则适用于IRIS支持的所有排序规则。对于出于兼容性原因仍在使用的旧归类,如`“pre-ISM-6.1”`,下标的规则有更多限制。例如,字符下标不能以控制字符作为其初始字符;整数下标中可以使用的位数也有限制。**
## 全局变量节点
在应用程序中,节点通常包含以下类型的结构:
1. 字符串或数字数据,包括本机`Unicode`字符。
2. 具有由特殊字符分隔的多个字段的字符串:
```java
SET ^Data(10) = "Smith^John^Boston"
```
可以使用ObjectScript `$PIECE` 函数来拆分这些数据。
3. InterSystems IRIS `$LIST` 结构中包含多个字段。`$LIST`结构是包含多个长度编码值的字符串。它不需要特殊的分隔符。
4. 空字符串 (`""`)。在下标本身用作数据的情况下,实际节点中不存储任何数据。
5. 一个位串。如果全局变量用于存储位图索引的一部分,那么存储在节点中的值就是位字符串。位串是包含`1`和`0`值的逻辑压缩集的字符串。可以使用`$BIT`函数构造位串。
6. 更大的数据集的一部分。例如,对象和SQL引擎将流(`BLOB`)存储为全局中连续的`32K`节点系列。通过流接口,流的用户不知道流是以这种方式存储的。
请注意,任何全局节点都不能包含长度超过字符串长度限制的字符串,字符串长度限制非常长。
## 全局变量排序规则
在全局中,节点按排序(排序)顺序存储。
**应用程序通常通过将转换应用于用作下标的值来控制节点的排序顺序。例如,SQL引擎在为字符串值创建索引时,会将所有字符串值转换为大写字母,并在前面加上一个空格字符,以确保索引不区分大小写并且以文本形式排序(即使数值存储为字符串)。**
# 全局变量引用的最大长度
**全局变量引用(即对特定全局节点或子树的引用)的总长度限制为`511`个编码字符(少于`511`个键入字符)。**
要保守地确定给定全局变量引用的大小,请使用以下准则:
1. 全局变量名称:每个字符加`1`。
2. 对于纯数字下标:每个数字、符号或小数点加`1`。
3. 对于包含非数字字符的下标:为每个字符添加`3`。
如果下标不是纯数字的,则根据用于编码字符串的字符集的不同,下标的实际长度会有所不同。一个多字节字符最多可以占用`3`个字节。
请注意,ASCII字符可能占用`1`或`2`字节。
如果排序规则进行大小写折叠,那么`ASCII`字符可以使用`1`个字节表示字符,`1`个字节表示消除歧义字节。
如果排序不执行大小写折叠,`ASCII`字符占用`1`字节。
4. 每个下标加`1`。
如果这些数字的总和大于`511`,则引用太长。
由于确定限制的方式,如果必须使用长下标或全局名称,这有助于避免使用大量下标级别。
相反,如果使用多个下标级别,则应避免长全局名称和长下标。
因为无法控制正在使用的字符集,所以保持全局名称和下标更短是很有用的。
当对特定引用有疑问时,创建与最长预期全局变量引用长度相等(甚至稍长一点)的全局变量引用的测试版本是有用的。
这些测试的数据为构建应用程序之前可能修订的命名约定提供了指导。
文章
Jingwei Wang · 九月 20, 2022
1. VMWare快照引起的网络中断导致非计划内主备机切换问题
1.1 问题描述
在创建虚拟机快照时,虚拟机需要短时间的冻结,这个短时间冻结通常指虚拟机静默,在静默过程中网络连接处于中断状态。由于数据库的不断增长,使用VMWare快照的方式对虚拟机进行备份的时长也会不断增加,当对虚拟机进行快照的时长长于InterSystems镜像服务质量 (QoS) 超时时间,即当主机网络中断超过QoS超时时间,仲裁机与备机观察并相互确认与主机的连接丢失后,将发起切换过程,使原备机成为主机并将虚拟IP从主机MAC地址解绑后重绑定到备机的MAC地址上。特别需要注意的是,在这种由于网络中断引起的切换中,仲裁与备机都无法得知主机的实际工作状态。因此,在主机网络连接恢复后,为了为了避免因切换期间主机还在处理数据导致主备机间数据不一致,备机主动发起请求让主机下线,关闭主机,此时主机状态显示为关闭(Down)。
1.2 解决方案
对于由于虚拟机快照引起的网络中断造成的非计划内主备切换问题,请参考以下两种解决方案:
使用数据库冻结/解冻脚本,具体脚本和操作方式请参考社区文章虚拟机备份和 Caché 冻结/解冻脚本,如有其他疑问请联系InterSystems WRC
在镜像集群中增加一个异步镜像成员,使用异步镜像成员创建虚拟机快照,由于此异步镜像成员也会同步获取主机数据,但是不会自动切换,所以在此异步镜像成员中创建虚拟机快照,既可以备份虚拟机,也不会引起非计划内主备机切换问题。
2. VMWare资源不足导致的主备机非计划内切换问题:
2.1 问题描述
当虚拟机的物理资源不足,可能会导致网络中断或者InterSystems IRIS 实例日志守护进程不响应超过 30 秒(或300 秒),导致主备非计划内切换。
2.2 解决方案
请扩展虚拟机的物理资源,且增加对虚拟机的状态进行监控,以防再次出现资源不足情况。
监控网络状态Log
由于网络中断造成的镜像主备切换是非计划内主备切换的重要原因之一,所以为了方便排查问题,可以在仲裁机上加一个ping的脚本,用来ping主机和备机,并将ping的结果放入log中,当发生非计划内主备切换时这个log有利于排查问题。也可以使用此ping脚本来监控网络状态,使用户能够第一时间获得网络状态信息。
文章
Michael Lei · 六月 21, 2022
如果您使用InterSystems技术开发了自己的网络应用,现在想在客户端进行验证码验证,以确定用户真实性使其更加安全。有一些现代框架可以解决验证码的问题,然而它们中的大多数需要互联网接入来生成代码,有时实施起来很复杂。考虑到图像识别已经非常成熟,您可以参考本文为基本例子。这就是为什么现在倾向于看到更多的模式识别验证码而不是单纯的阅读验证码。(例如,点击所有有店面的图片)。如果你需要更复杂的东西,请继续开发,改进这个代码并分享它。 继续阅读以了解如何使用这个基本的例子:
Demo.Captcha class
使用这个类,你可以在一个物理目录上创建验证码图像文件,以便在你的应用程序上显示。请注意,创建图像的目录必须是可用的,以便你的Web应用程序访问这些图像。要创建验证码图像,请调用以下方法,将完整的文件名作为一个参数:
创建 image 文件
Set tCount = $Increment(^CacheTemp("CAPTCHA",0)) Set tPath = "C:\InterSystems\Ensemble201710\CSP\user\images\captcha\"If '##class(%File).DirectoryExists(tPath) { Set tSC = ##class(%File).CreateDirectoryChain(tPath) } Set tFileName = %session.SessionId_tCount_".bmp" Set tFullName = tPath_tFileNameSet tCaptcha = ##class(Demo.Captcha).CreateImage(tFullName) Write tCaptcha,!
在 System/系统 > Security Management/安全管理 > Web Applications/Web 应用 > Edit Web Application/编辑Web应用菜单下添加“\images\captcha\” , 请注意 CSP 文件物理路径在上面代码里是一样的。
运行上面的代码来创建验证码图像后,请看一下该路径。你会看到所有生成的验证码图像如下(注意,你需要一个%session对象):
Demo.Captcha类中的CreateImage()方法也将返回生成的验证码,它将允许你在你的Web应用程序上对用户输入的验证码进行验证。
例子
为了使大家的工作简单点,我准备了一个简单的CSP文件,可以渲染一个验证码图像并进行验证。你可以导入所附的XML文件,并根据需要验证和改变路径以匹配你的CSP Web应用。
安装在USER命名空间上,打开Studio并导入XML文件;
在浏览器上打开 captcha.csp 文件;
点击 “change image/换一张” 按钮 来创建和显示新的captcha图像;
在空白输入框中输入图像代码;
点击验证按钮并检查信息;
导入类
打开 Studio;
选择 USER 命名空间;
到Tools/工具->Import Local导入本地 菜单下并选择你下载好的 captcha.xml ;
根据下图导入需要的类;
根据你的CSP Web应用改变验证码图像路径;
在浏览器通过点击浏览网页按钮 打开captcha.csp 文件;
如果你需要改变图像,点击改变图像按钮;
查看验证码图像目录;
在空白输入框中输入验证码,并点击验证;
查看结果;
随意重复这些步骤;
希望这些能帮助到您,欢迎随时联系我们.
Fábio Gonçalves
Sales Engineer - Intersystems Brazil
文章
姚 鑫 · 五月 30, 2021
# 第十一章 发送和接收IBM WebSphere MQ消息
InterSystems IRIS为IBM `WebSphere MQ`提供了一个接口,可以使用该接口在InterSystems IRIS和IBM `WebSphere MQ`的消息队列之间交换消息。要使用此接口,必须能够访问IBM `WebSphere MQ`服务器,并且IBM `WebSphere MQ`客户端必须与InterSystems IRIS在同一台计算机上运行。
该接口由`%Net.MQSend`和`%Net.MQRecv`类组成,这两个类都是`%Net.abstractMQ`的子类。这些类使用由InterSystems IRIS在所有合适的平台上自动安装的动态链接库。(这是Windows上的`MQInterface.dll`;其他平台的文件扩展名不同。)。反过来,InterSystems IRIS动态链接库需要IBM `WebSphere MQ`动态链接库。
该界面仅支持发送和接收文本数据,不支持二进制数据。
# 使用IBM WebSphere MQ的RIS接口
通常,要使用IBM `WebSphere MQ`的InterSystems IRIS接口,请执行以下操作:
1. 确保有权访问`IBM WebSphereMQv7.x`或更高版本。具体而言:
- IBM `WebSphere MQ`客户端必须与InterSystems IRIS安装在同一台计算机上。请注意,安装程序会根据需要更新`PATH`环境变量并添加其他系统变量。
- 确保在安装客户端后重新启动计算机,以便InterSystems IRIS能够识别该客户端。
- 客户端必须能够访问IBM `WebSphere MQ`服务器。
- 将用来访问服务器的用户名必须具有使用队列管理器和计划使用的队列的权限。
2. 创建`%Net.MQSend`或`%Net.MQRecv`的新实例,具体取决于要发送还是接收消息。
3. 连接到IBM `WebSphere MQ`服务器。执行此操作时,您需要提供以下信息:
- 队列管理器的名称。
- 要使用的队列的名称。
- 与该队列通信的通道。可以指定IBM `WebSphere MQ`服务器的通道名称、传输机制以及IP地址和端口。
如果正在使用IBM `WebSphere MQ`的身份验证功能,还可以提供名称和密码。
4. 调用`%Net.MQSend`或`%Net.MQRecv`的相应方法来发送或接收消息。
注意:要在64位Linux平台上使用IBM `Websphere MQ`,必须设置`LD_LIBRARY_PATH`以包括`MQ`库的位置。因为必须为任何使用`MQ`接口的InterSystems IRIS进程设置路径,所以如果正在运行后台进程,则必须在启动InterSystems IRIS之前设置该路径,并在运行IRIS终端之前在任何UNIX®终端中设置该路径。
## 获取错误代码
`%Net.MQSend`和`%Net.MQRecv`的方法如果成功则返回1,如果不成功则返回0。在出现错误的情况下,调用`%GetLastError()`方法,该方法返回IBM `WebSphere MQ`给出的最后一个原因代码。
# 创建连接对象
在可以通过IBM `WebSphere MQ`发送或接收消息之前,必须创建一个`Connection`对象,该对象可以建立到队列管理器的连接、打开通道和打开队列以供使用。有两种方法可以做到这一点:
- 可以使用`%Init`方法,该方法接受指定所有所需信息的参数。
- 可以在首次设置指定所有所需信息的属性后使用`%Connect`方法。
## 使用%Init()方法
要使用`%Init()`方法创建连接对象,请执行以下操作:
1. 创建`%Net.MQSend`(如果要发送消息)或`%Net.MQRecv`(如果要接收消息)的实例。本主题将此实例称为连接对象。
注意:如果收到 ``错误,则表示缺少动态链接库,并且`messages.log`文件(在系统管理器的目录中)有更多详细信息。
2. 如果需要身份验证,请设置`Connection`对象的以下属性:
- 用户名-指定有权使用此频道的用户名。
- 密码-指定给定用户的密码。
3. 调用`Connection`对象的`%Init()`方法。此方法按顺序接受以下参数。
a. 指定队列名称的字符串;这应该是指定队列管理器的有效队列。
b. 指定队列管理器的字符串;它应该是IBM `WebSphere MQ`服务器上的有效队列管理器。
如果省略此参数,系统将使用IBM `WebSphere MQ`中配置的默认队列管理器。或者,如果IBM `WebSphere MQ`已配置为队列管理器由队列名称确定,则系统将使用适合给定队列名称的队列管理器。
c. 指定频道规范的字符串,格式如下:
```java
"channel_name/transport/host_name(port)"
```
这里,`channel_name`是要使用的通道的名称,`Transport`是通道使用的传输,`host_name`是运行IBM `WebSphere MQ`服务器的服务器名称(或IP地址),`port`是该通道应该使用的端口。
传输可以是以下之一:`TCP`、`LU62`、`NETBIOS`、`SPX`
例如:
```java
"CHAN_1/TCP/rodan(1401)"
```
```java
"CHAN_1/TCP/127.0.0.1(1401)"
```
如果省略此参数,系统将使用IBM `WebSphere MQ`中配置的默认通道规范。或者,如果系统已配置为通道由队列名称确定,则系统使用适合给定队列名称的通道。
d. 一个可选字符串,它指定要向其中写入错误消息的日志文件。默认情况下,不进行日志记录。
4. 检查`%Init()`方法返回的值。如果该方法返回1,则表明连接已成功建立,可以使用`Connection`对象发送或接收消息(具体取决于使用的类)。
## 使用%Connect()方法
在某些情况下,可能更喜欢单独指定连接的所有详细信息。为此,请使用`%Connect()`方法,如下所示:
1. 创建`%Net.MQSend`(如果要发送消息)或`%Net.MQRecv`(如果要接收消息)的实例。如前所述,本主题将此实例称为连接对象。
注意:如果收到`` 错误,则表示缺少动态链接库,并且`messages.log`文件(在系统管理器的目录中)有更多详细信息。
2. 设置`Connection`对象的以下属性:
- `QName`-(必选)指定队列名称;这应该是指定队列管理器的有效队列。
- `QMgr`-指定要使用的队列管理器;它应该是IBM `WebSphere MQ`服务器上的有效队列管理器。
如果省略此参数,系统将使用IBM `WebSphere MQ`中配置的默认队列管理器。或者,如果IBM `WebSphere MQ`已配置为队列管理器由队列名称确定,则系统将使用适合给定队列名称的队列管理器。
3. 或者,通过设置`Connection`对象的以下属性来指定要使用的频道:
- `Connection` - 指定IBM `WebSphere MQ`服务器的主机和端口。例如:`"127.0.0.1:1401"`。
- `Channel` - 指定要使用的频道的名称。这必须是IBM WebSphere MQ服务器上的有效通道。
- `Transport` - 指定通道使用的传输。此属性可以是以下之一: `"TCP"`, `"LU62"`, `"NETBIOS"`, `"SPX"`
如果省略这些参数,系统将使用IBM `WebSphere MQ`中配置的默认通道规范。或者,如果系统已配置为通道由队列名称确定,则系统使用适合给定队列名称的通道。
4. 如果频道需要身份验证,请设置`Connection`对象的以下属性:
- 用户名-指定有权使用此频道的用户名。
- 密码-指定给定用户的密码。
5. 调用`Connection`对象的`%ErrLog()`方法。此方法接受一个参数,即要用于此连接对象的日志文件的名称。
6. 检查`%ErrLog()`方法返回的值。
7. 调用`Connection`对象的`%Connect()`方法。
8. 检查`%Connect()`方法返回的值。如果该方法返回1,则表明连接已成功建立,可以使用`Connection`对象发送或接收消息(具体取决于您使用的类)。
# 指定字符集(CCSID)
要设置用于消息转换的字符集,请调用`Connection`对象的`%SetCharSet()`方法。指定在IBM `WebSphere MQ`中使用的整数编码字符集`ID(CCSID)`。
- 如果正在发送消息,这应该是这些消息的字符集。如果不指定字符集,则MQ系统假定消息使用为`MQ`客户端指定的默认字符集。
- 如果要检索邮件,则这是要将这些邮件翻译为的字符集。
要获取当前正在使用的`CCSID`,请调用`%charset()`方法。此方法通过引用返回`CCSID`,并返回1或0以指示是否成功.
# 指定其他消息选项
要指定消息描述符选项,可以选择设置连接对象的以下属性:
- `ApplIdentityData`指定应用程序标识消息描述符选项。
- `PutApplType`指定`PUT Application Type`消息描述符选项。
## 发送消息
要发送邮件,请执行以下操作:
1. 按照“创建连接对象”中的说明创建连接对象。在这种情况下,请创建`%Net.MQSend`的实例。`Connection`对象有一个消息队列,可以向该队列发送消息。
2. 根据需要调用以下方法:
- `%put()`-给定一个字符串,此方法将该字符串写入消息队列。
- `%PutStream()`-给定初始化的文件字符流,此方法将该字符串写入消息队列。请注意,必须设置流的`Filename`属性才能对其进行初始化。不支持二进制流。
- `%SetMsgId()`-给定一个字符串,此方法使用该字符串作为发送的下一条消息的消息ID。
3. 检查调用的方法返回的值。
4. 检索完消息后,调用`Connection`对象的`%Close()`方法以释放动态链接库的句柄。
示例1:`SendString()`
下面的类方法使用队列管理器`QM_antigua`和名为 `S_antigua`的队列通道向队列`mqtest`发送一条简单的字符串消息。通道使用TCP传输,IBM `WebSphere MQ`服务器运行在名为`Antigua`的机器上,并侦听端口1401。
```java
///Method returns reason code from IBM WebSphere MQ
ClassMethod SendString() As %Integer
{
Set send=##class(%Net.MQSend).%New()
Set queue="mqtest"
Set qm="QM_antigua"
Set chan="S_antigua/TCP/antigua(1414)"
Set logfile="c:\mq-send-log.txt"
Set check=send.%Init(queue,qm,chan,logfile)
If 'check Quit send.%GetLastError()
//send a unique message
Set check=send.%Put("This is a test message "_$h)
If 'check Quit send.%GetLastError()
Quit check
}
```
示例2:`SendCharacterStream()`
下面的类方法发送文件字符流的内容。它使用的队列与上一个示例中使用的队列相同:
```java
///Method returns reason code from IBM WebSphere MQ
ClassMethod SendCharacterStream() As %Integer
{
Set send=##class(%Net.MQSend).%New()
Set queue="mqtest"
Set qm="QM_antigua"
Set chan="S_antigua/TCP/antigua(1414)"
Set logfile="c:\mq-send-log.txt"
Set check=send.%Init(queue,qm,chan,logfile)
If 'check Quit send.%GetLastError()
//initialize the stream and tell it what file to use
Set longmsg=##class(%FileCharacterStream).%New()
Set longmsg.Filename="c:\input-sample.txt"
Set check=send.%PutStream(longmsg)
If 'check Quit send.%GetLastError()
Quit check
}
```
示例3:从终端发送消息
以下示例显示了向IBM `WebSphere MQ`队列发送消息的终端会话。这只能在配置了IBM `WebSphere MQ`客户端的计算机上运行。
```java
Set MySendQ = ##class(%Net.MQSend).%New()
Do MySendQ.%Init("Q_1", "QM_1","QC_1/TCP/127.0.0.1(1401)","C:\mq.log")
Do MySendQ.%Put("Hello from tester")
Set MyRecvQ =##class(%Net.MQRecv).%New()
Do MyRecvQ.%Init("Q_1", "QM_1","QC_1","C:\mq.log")
Do MyRecvQ.%Get(.msg, 10000)
Write msg,!
```
文章
Hao Ma · 一月 10, 2021
本文讨论 Windows 写入缓存设置,该设置会使系统在断电或操作系统崩溃的情况下容易发生数据丢失或损坏。 该设置在某些 Windows 配置中默认开启。
为磁盘启用 Windows 写入缓存意味着 Caché(或任何程序)写入该磁盘的某些内容不一定会立即提交到持久性存储(即使 Caché 在其写入阶段的特定关键点刷新从操作系统缓存到磁盘的写入也是如此)。 如果计算机断电,为该设备缓存的任何内容都会丢失,除非该设备的缓存是非易失性的或者由电池供电。 Caché 依靠操作系统来保证数据的持久性。 在这种情况下,保证是无效的。 对于 Caché 来说,这可能会导致数据库损坏或者数据库或日志文件中的数据缺失。
InterSystems 的文档显示,使“写入映像日志”提供的保证失效的一种情况是回写缓存内容丢失(请参见 [http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCDI_wij#GCDI/wij_limits](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCDI_wij#GCDI_wij_limits))。 InterSystems 全球响应中心的数据完整性团队研究了许多 Windows 平台上的数据丢失或损坏案例,这些案例中有证据表明,回写缓存内容丢失是由该设置的值导致的。
值得一提的是,磁盘的缓存可能会有效防止发生此类问题。 如果相关磁盘的缓存是非易失性的或由电池供电,则即使开启该设置,写入磁盘也应该是安全的。 如果相关存储比直接连接的磁盘更复杂,您需要了解在该存储基础架构的何处对写入进行缓存,以及这些缓存是否是易失性的或者是否由电池供电,以评估风险。
您可以转到“设备管理器”,展开“磁盘驱动器”部分,然后查看给定磁盘的属性来查看设置。 我们感兴趣的设置在“策略”选项卡上。

界面上的用词并不总是与您在这里看到的相同,可能因设备类型的不同而有所不同。 不过,这是常见的用词表述,并且 Windows 明确指出,开启该设置后,如果机器断电或崩溃,系统可能会发生数据丢失。
接下来是同一机器上另一个磁盘的示例,其中的影响没有那么明显。在这里选择“更好的性能”将与在另一个示例中选择“启用写入缓存”带来相同问题。

在这两个示例中,您看到的选定设置都是该设备的默认设置,我没有更改过。 您可以看到,在第一个示例中,默认设置使设备处于风险之中,而第二个示例则没有。 据我所知,并没有通用于所有设备类型或 Windows 版本的默认设置。 换句话说,需要在每台设备上检查此设置,以了解设备是否存在此风险。
作为系统管理员,处理这种情况有三种基本方法。 禁用该设置是最简单的方法,可确保不会面临此风险。 但是,禁用该设置可能会对性能产生不可接受的影响。 如果是这种情况,您可能更愿意开启该设置,并将计算机连接到不间断电源。 这样做可以防止断电导致的数据丢失或损坏,因为 UPS 应该可以在断电时提供足够的时间让您从容地关机。 最后一个选择是简单地接受服务器断电或崩溃时数据丢失的风险。 InterSystems 建议不要采用此方式。 消费级 UPS 已相当便宜,而且检测完整性问题并从中恢复可能非常耗时又会产生问题。
InterSystems 建议您在未确保计算机连接到不间断电源的情况下不要开启此设置。 如果存储是外部设备,则该设备也需要连接到 UPS。
文章
姚 鑫 · 五月 14, 2021
# 第六章 临时全局变量和IRISTEMP数据库
对于某些操作,可能需要全局变量的功能,而不需要无限期保存数据。例如,可能希望使用全局对某些不需要存储到磁盘的数据进行排序。对于这些操作,`InterSystems IRIS`提供了临时全局机制。该机制的工作方式如下:
- 对于应用程序名称空间,可以定义一个全局映射,以便将具有特定命名约定的全局变量映射到`IRISTEMP`数据库,该数据库是一个特殊的数据库,如下所述。
例如,可以定义一个全局映射,以便将名称为`^AcmeTemp*`的所有全局变量映射到`IRISTEMP`数据库。
- 当代码需要临时存储数据并再次读取它时,代码将向使用该命名约定的全局变量写入数据,并从全局变量读取数据。
例如,要保存值,代码可能会执行以下操作:
```java
set ^AcmeTempOrderApp("sortedarray")=some value
```
然后,稍后代码可能会执行以下操作:
```java
set somevariable = ^AcmeTempOrderApp("sortedarray")
```
**通过使用临时全局变量,可以利用`IRISTEMP`数据库没有日志记录这一事实。因为数据库没有日记记录,所以使用该数据库的操作不会产生日记文件。日志文件可能会变得很大,并可能导致空间问题**。但是,请注意以下几点:
不能回滚修改`IRISTEMP`数据库中的全局变量的任何事务;此行为特定于`IRISTEMP`。如果需要通过事务管理临时工作,请不要使用`IRISTEMP`中的全局变量来实现此目的。
请注意,仅对不需要保存的工作使用`IRISTEMP`。
# 定义临时全局变量的映射
要定义临时全局变量的映射,请执行以下操作:
1. 选择一个命名约定,并确保所有开发人员都知道这一点。请注意以下几点:
- **考虑是要有多个临时全局变量还是要少一些具有多个节点的临时全局变量。与读取或写入相同数量的独立全局变量相比,`InterSystems IRIS`更容易高效地读取或写入同一全局变量中的不同节点。这种效率差异对于少数全局变量来说可以忽略不计,但当有数百个独立的全局变量时,效率差异就非常明显。**
- 如果计划在多个名称空间中使用相同的全局映射,那么设计一个系统,使一个名称空间中的工作不会干扰另一个名称空间中的工作。例如,可以使用命名空间名称作为全局变量中的下标。
- 类似地,即使在一个命名空间内,也要设计一个系统,使代码的每个部分在同一全局中使用不同的全局或不同的下标,以避免干扰。
- 请勿使用系统保留的全局名称。
2. 在管理门户中,导航到命名空间页面(System Administration > Configuration > System Configuration > Namespaces)。
3. 在应用程序命名空间所在的行中,单击Global Mappings。
4. 在全局映射页面中,单击新建全局映射。
5. 对于全局数据库位置,选择`IRISTEMP`。
6. 对于全局名称,输入以星号(`*`)结尾的名称。不要包括名称的第一个插入符号。
例如: `AcmeTemp*`
此映射会导致名称以`AcmeTemp*`开头的所有全局变量映射到`IRISTEMP`数据库。
7. 单击OK。
注意:>> 显示在新映射行的第一列中,表示已打开映射进行编辑。
8. 要保存映射以便InterSystems IRIS使用它们,请单击保存更改。




# IRISTEMP的系统使用
请注意,InterSystems使用临时全局变量作为临时空间,例如,在执行某些查询(用于排序、分组、计算聚合等)期间用作临时索引。
IRISTEMP中包含的一些系统全局变量包括:
- `^IRIS.Temp*`
- `^mtemp*`
永远不要更改这些全局变量中的任何一个。
文章
Frank Ma · 七月 28, 2022
应用集成平台市场上产品众多,商家专家观点纷纭,莫衷一是。Gartner公司从用户角度出发,搭建了Peer Insight “大众点评”平台,让用户能够为自己使用的产品发声,对各个产品打分。以下是来自用户的声音,供参考。
第一款产品是微软的BizTalk,综合得分3.9。
第二款产品是InterSystems的Ensemble,综合得分4.6。
第三款产品是IBM的WebSphere Enterprise Service Bus,综合得分3.8。
BizTalk by MicroSoft
Ensemble by InterSystems
WebSphereEnterprise Services Busby IBM
总体评价:57%的用户愿意推荐该产品
总体评价:88%的用户愿意推荐该产品
总体评价:55%的用户愿意推荐该产品
分项评分
分项评分
分项评分
综合能力得分
综合能力得分
综合能力得分
评估与签约 3.3 定价灵活性
4.0 理解需求的能力
评估与签约 4.2 定价灵活性
4.6 理解需求的能力
评估与签约 3.5 定价灵活性
4.0 理解需求的能力
集成与部署 3.4 部署便利性 3.3 终端用户培训的质量 3.9 使用标准API和工具进行集成的便利性 3.1 第三方资源的可用性
集成与部署 4.3 部署便利性 4.3 终端用户培训的质量 4.3 使用标准API和工具进行集成的便利性 4.3 第三方资源的可用性
集成与部署 4.6 部署便利性 4.2 终端用户培训的质量 4.0 使用标准API和工具进行集成的便利性 4.1 第三方资源的可用性
服务与支持 4.0 供应商回应的及时性
3.7技术支持的质量
3.4 同行用户群的质量
服务与支持 4.6 供应商回应的及时性
4.6技术支持的质量
4.2 同行用户群的质量
服务与支持 4.0 供应商回应的及时性
4.3技术支持的质量
4.1 同行用户群的质量
更多信息请参考 Gartner英文原文。
文章
Michael Lei · 八月 8, 2022
医疗行业的互操作性在改善病人护理、降低医疗服务提供者的成本以及为提供者提供更准确的情况方面发挥着重要作用。然而,由于有这么多不同的系统,数据的格式也有很多不同的方式。有许多标准被创造出来以试图解决这个问题,包括HL7v2、HL7v3和CDA,但每一种都有其缺点。
FHIR,即快速医疗互操作性资源,是一种新的医疗数据格式,旨在解决这些问题。它是由国际卫生级七组织(HL7)开发的,该组织还开发了HL7v2、HL7v3和CDA。
今天我们将探讨如何在VS代码中借助IntelliSense和自动完成功能,通过使用FHIR Schema 创建和验证FHIR资源。
第 1 步 :从FHIR 官方网站 https://www.hl7.org/fhir/下载 JSON schema file 文件用来做资源校验
第 2 步: 创建文件夹(在这个例子中,我使用病人文件夹和病人资源),并将提取的fhir.schema.json文件复制到同一文件夹,然后从VS Code中打开文件夹
第 3 步: 通过修改setting.json文件,设置VS代码以识别FHIR模式。按CTRL+SHIFT+P并输入工作区设置JSON文件
第 4 步: 在同一文件夹中创建一个新文件patient.fhir.json。按Ctrl+Space,你将通过IntelliSense获得FHIR资源的所有属性
添加资源类型 "病人",与病人资源有关的所有属性将出现在IntelliSense中。
VS Code 讲自动校验资源的结构和语法。
在IntelliSense和自动完成的帮助下,我们已经创建并验证了我们的病人资源。
第 5 步: 使用Postman的Rest API在InterSystems FHIR服务器上发布创建资源。
通过使用获取方法检索已创建的病人资源。
恭喜你!,我们已经创建、验证了我们的病人资源,并成功地使用postman发布和检索到InterSystems FHIR服务器。通过这种方式,我们可以轻松地创建和验证任何FHIR资源。
文章
Johnny Wang · 一月 30, 2022
我的几个孩子都很喜欢手工艺品,您可能会觉得作为一个父亲我会用夸张的表情表扬他们很有创意然后还拍照片发到Pinterest(世界上最大的图片社交分享网站)上去,但是我从来都没这么做过。我肯定爱我的孩子,我也确实认为他们有创意,但老实讲如果你有一个正上小学的孩子,你肯定很清楚他们实际的水平。
首先,要去制作一个手工艺品,你得先在油管上面看五分钟的教学视频,在此之前你可能已经浏览过大量的同类视频,你也知道那些标题党起的“五分钟教你学会”的题目就是在骗你点进去,但你可能刷着刷着手机就过去了五个钟。这类视频无非是一个人拿着一个彩色的塑料瓶,或者一个有光泽的鞋盒,把所有东西切开、用胶带和胶水粘在一起,然后你就获得了一个精美无比但是根本没用的艺术品,但至少拍照片发个朋友圈看起来还蛮不错。
第二步,你小孩看完视频了,也想自己动手做。老实讲你没法拒绝这种能够锻炼他们创意的好机会,这绝对是寓教于乐的好机会,你也把那些瓶子、纸板箱和其他的垃圾重新利用起来了。这些视频往往十分重要,这说不定会影响他们以后成为成功的设计师、建筑师或者行业精英。
再然后,关键的东西来了:胶水。
我家的手工艺品购买预算(您别说真有这么个预算)几乎都花在了买胶水或者胶带上,在过去几年中,我都在用一种叫做“和纸”的带光泽的胶带、用来打胶的胶枪和会发光的百特棒,它贴在厨房或者餐桌等等地方就会很亮。还好我现在的工作让我承担得起这些花费,但同样让人沮丧的是大部分钱都被花在胶带胶水这种辅助工具上,而不是花在提升手工艺品的质量上。
系统之间的数据流成本很高
当我看到企业架构师描述他们的环境时,我经常有一种感觉,同时这种感觉也经常让我觉得挫败。那些架构师将经过验证的开源技术(比如 Postgres 和 MySQL 或他们的云版),与一种或多种花哨的专用技术(如 Clickhouse、TimescaleDB 或 CouchBase)结合到一个数据架构中。从表面上看,这完全有道理。 我们非常感谢那些经过验证的开源技术,作为一名技术专家,我经常对这些用于特殊用途的解决方案所产生的创新印象深刻。 然而,这种方法产生的复合数据架构通常不像预期的那么简单或预算友好,这与我的孩子经常要求增加手工艺品预算的原因相同:胶水不够用了。
一个好的数据管道或 ETL 软件并不便宜,构建这些数据流的数据工程师或顾问也不便宜。 更糟糕的是,就像我孩子的胶带会磨损一样,系统之间的数据流需要昂贵的维护,因为它们需要保持运行的时间也很长,这绝不是一个5分钟的手工艺品视频讲得清楚的事情。
采用统一技术的高效数据架构
像 InterSystems IRIS 这样的统一数据平台提供了事务处理和分析工作负载的数据架构,并通过许多不同的数据模型提供高效的并发访问,所有这些都采用统一技术。 通过在 InterSystems IRIS 上构建你的应用程序、数据仓库和其他解决方案,你可以节省大量粘合和手动工作,而不会牺牲处理您的用例所要求的特殊用途数据,因为没有复制、同步或推送你的数据。 更重要的是,使用这种类型的数据架构,您最终将获得在医疗保健、金融服务和许多其他行业中已经得到证明的弹性,而不是五种不同工具的最小公分母。
回到手工艺品的话题上,我希望未来每隔一周左右我问我的孩子们的问题能够变成这样:“我不是不要你的创意; 我只是要求你少用胶水。”
关于作者:Benjamin DeBoe
Benjamin 是 InterSystems 数据平台组的产品经理,负责可扩展性和分析领域。 作为 InterSystems 收购 iKnow 的一份子,他于 2010 年加入 InterSystems,并曾使用各种数据库技术,主要在数据仓库、自然语言处理和任何分析领域。
点击查看原文链接 乐高就是不用胶水的创造,中国传统的木结构(榫卯)也是不需要胶水的,最好/稳固的创造/搭建都是不用胶水的。。。 这个类比非常到位了