Domino用户同步MySQL与Windows服务启动问题实战解析
2026/9/7 23:12:33 网站建设 项目流程

简介:《Domino开发指南精华》是一份PDF格式的技术文档,面向需要构建企业级协作应用的Java开发者,也适合刚接触Lotus Notes/Domino平台的初学者,旨在帮助读者掌握Domino环境下的Java集成开发技能,解决企业沟通与文档管理场景中的具体问题。文档围绕lotus.domino包系统讲解Java集成开发,涵盖数据库操作、文档管理、视图控制、代理自动化等核心主题,并配有大量示例代码,可学会邮件发送与接收、富文本处理、URL头信息获取等实用功能。除基础用法外,书中还讨论了企业环境中的开发技术实施、现有Domino架构下的功能扩展与优化,能够指导开发者把协作能力落地到实际业务系统,并通过视图与代理调优提升应用响应速度和用户体验。资源为单个PDF文件,大小3.82MB,下载后可离线阅读,目前已有1925人学习下载。借助书中的完整示例和对开发工具集的说明,读者既能快速搭建Domino开发环境,也能将文档管理、视图控制与代理自动化串联成完整的企业协作方案,适合作为案头参考。 先说个真实场景:我在搜索引擎上看到有人提问“如何把Domino用户同步到MySQL里”,下面紧跟着一堆答非所问的回复;还有人反复追问“为什么必须先停止服务,才能打开桌面的Domino Server”。这些问题的背后,说明Notes/Domino虽然被很多人当成“上古遗产”,但在银行、制造业、政府机关的办公自动化里,它依然是每天流转审批单、公文、会议纪要的核心枢纽。开发人员一代代换,平台却一直没走,于是“怎么和现代技术栈打通”就成了大多数Domino从业者真正关心的事。这篇文章,我就围绕这两个高频问题,把Domino开发里最核心的原理、最常用的集成方案、以及我踩过的坑一锅端出来,希望能给正在和Domino打交道的朋友一点实在参考。

1. 先把Domino的家底摸清楚:文档型数据库和它的一套处世哲学

1.1 不是数据库,胜似数据库:一切皆文档

Domino底层是文档型数据库,不是关系型数据库。你往库里存一张审批单、一篇公告、一条待办,都是一份“文档”(Document)。文档里的字段(Field)既可以存字符串、数字、日期,也可以存富文本(RichText)、文件附件,甚至一个字段里塞多个值。这种模型在企业办公场景里非常占便宜:一张采购申请单要附带合同附件、多级审批意见、历史修改记录,如果用关系型数据库,你得建主表、子表、附件表、审批流表,再加一堆关联查询,而在Domino里直接一个文档全装下,视图里还能把任意字段作为列展示。

这种设计也带来不少开发上的习惯差异。关系型数据库的开发者习惯先设计表结构,再写业务逻辑;Domino开发者则是先想清楚“一张单子上要放哪些字段”,然后直接画表单(Form),字段拖上去就能用。改动字段就像改Word文档一样随意,不需要执行ALTER TABLE。这个“随手就能加字段”的灵活性在原型阶段特别爽,但也埋了一个隐患:如果没有严格的命名规范,同一个含义的字段在多个表单里可能叫法不同,后期做数据汇总时会被字段名差异搞到崩溃。

1.2 单机一体化的架构对开发者的真实影响

Domino Server本身用一个安装包就把HTTP服务、邮件路由、复制服务、代理运行环境、目录服务(LDAP)全包了。这种一体化设计让部署变得非常简单:一台Windows或Linux服务器,装好Domino,配个域名,把notes.ini一改,应用、邮件、企业通讯录就都跑起来了。相比现在动不动就微服务拆分、容器编排那套,Domino显得“土”,但在中小型企业的IT环境里,这种一体化恰恰是它的生存优势——一个运维就能管完,不用养一整个中间件团队。

但对开发者和运维来说,一体化也意味着“牵一发动全身”。Domino的HTTP服务、路由服务、复制任务、定时代理,都跑在同一个进程里(Windows上是nserver.exe,UNIX/Linux上通常是单个server进程)。你在notes.ini里改一个参数,影响的可能是全部服务;你写的一个Java代理如果死循环,可能导致整个服务器响应变慢,连邮件都跟着遭殃。所以要学会按照模块去隔离问题,先在服务器控制台上敲tell http quit停掉HTTP任务再看其他服务是否正常,而不是一上来就重启整个Domino服务。

1.3 谁还在用Domino,用在哪

我接触到的Domino大型客户,主要有三类。一类是大型金融机构,把Domino当作内部OA和邮件系统,审批流、发文、会议纪要在上面运行了十几年,光历史数据就有几百GB,根本迁不动。第二类是制造型企业,把Domino用于供应链协同、经销商的订单填报和审核,因为支持离线复制,工厂网络不稳定也能先把数据存在本地,等联通了再同步。第三类是政府和事业单位,公文流转、督查督办这类强流程业务,Domino的工作流引擎和权限体系恰好能覆盖。了解这些场景就会明白,Domino开发核心不是追求技术新,而是追求稳定、可控、能跑十年不出大乱子。这也是后面所有方案选择的前提。

2. 把Domino用户同步到MySQL:方案对比与完整落地

2.1 为什么非要搬MySQL,直接读Domino不行吗

先说“为什么要同步”。Domino自带的目录服务(Domino Directory,俗称“公共通讯录”)保存了组织架构、人员账号、群组、邮件地址等核心主数据。但很多企业的BI报表、HR系统、企业微信、钉钉、或者统一门户,并不会直接对接Domino的LDAP或视图接口。于是业务部门拿着“人员名单要从OA同步到报表系统”这种需求来找你,而报表系统多数情况下只认MySQL或Oracle。所以,“用户同步”的本质,是把Domino这块“主数据孤岛”和外部系统打通。直接读Domino也不是不行——Domino提供了LDAP服务,外部系统可以用标准LDAP协议查询人员信息。但LDAP接口返回的数据格式和属性映射需要额外适配,而且在很多企业网络策略里,数据库直连比LDAP开放更容易被审批通过。更关键的是,Domino目录里的人员字段(如姓名、部门、邮箱、电话)未必能直接对应MySQL里的用户表结构,往往要做字段映射和清洗。于是,用程序定期把Domino用户表刷到MySQL中间表,就成了最常见的落地方式。

2.2 三条路线:LEI、JDBC代理、API网关

实现同步的方式大致有三类,我放在一起对比一下:

方式优点缺点适用场景
LEI(Lotus Enterprise Integrator)老牌专业工具,图形化配置,支持调度需要额外授权,配置相对复杂,新版本支持度一般已有LEI授权的企业,做大批量定时同步
Java代理 + JDBC灵活可控,无额外授权成本,逻辑全在代码里要自己处理连接、错误、增量逻辑,有开发量绝大多数开发团队的首选
外部API网关 + Domino REST APIDomino新版本提供REST接口,外部系统反过来拉取要求Domino版本较新,接口功能覆盖可能不够需要实时查询、外部主动拉的场景

从我的实践经验看,除非企业已经买了LEI授权,否则我一般推荐Java代理+JDBC。原因很简单:Domino开发服务器本身就支持Java代理,不需要额外装环境,逻辑写在代码里也方便走Git版本管理,后续加字段、改映射都好维护。LEI虽然听起来“专业”,但它的配置文件是专用的,找人接手都困难。

2.3 我用Java代理实现同步的完整过程

这里我给出一个可参考的实现思路。首先在Domino设计器里创建一个Java代理(Agent),类型选“后台Java代理”,触发方式按需求选“定时执行”。代理的核心逻辑分三步:连接Domino目录、读取人员文档、写入MySQL。

连接Domino目录这一步,用lotus.domino.Database对象打开当前服务器的names.nsf:

import lotus.domino.*; public class SyncUsersToMysql extends AgentBase { public void NotesMain() { try { Session session = getSession(); AgentContext ctx = session.getAgentContext(); // 打开Domino目录数据库 Database namesDb = session.getDatabase(ctx.getServer(), "names.nsf"); View personView = namesDb.getView("($Users)"); ViewNavigator nav = personView.createViewNav(); Document doc = nav.getFirstDocument(); while (doc != null) { String fullName = doc.getItemValueString("FullName"); String lastName = doc.getItemValueString("LastName"); String firstName = doc.getItemValueString("FirstName"); String mailAddr = doc.getItemValueString("MailAddress"); String dept = doc.getItemValueString("Department"); // 这里拿到人员字段后,交给JDBC写入 upsertToMysql(fullName, firstName, lastName, mailAddr, dept); Document tmp = nav.getNextDocument(doc); doc.recycle(); doc = tmp; } } catch (Exception e) { e.printStackTrace(); } } }

写MySQL侧的逻辑时,有一个很容易踩的坑:不要在Java代理里不带连接池地反复建立数据库连接。尤其当用户量上万时,每读一个人就DriverManager.getConnection一次,代理会拖慢整个Domino服务器。我通常的做法是在代理启动时创建连接,同步完批量提交后再关闭;数据量大时用PreparedStatementaddBatch/executeBatch分批写入。另外要注意在Domino代理里操作完的Document对象要及时调用recycle(),否则内存会飙升。

2.4 增量同步与账号对应关系的坑

全量同步在用户几百人时没问题,但几千人以上的企业,每次全量跑会带来无谓的负载。增量同步的思路是:在names.nsf里利用文档的LastModified属性,只取最近修改过的人员文档。实际操作时,可以通过视图按修改时间过滤,或者在Java代理里判断doc.getLastModified()是否大于上次同步时间戳。上次同步时间戳可以存在一个专门的配置文档里,不必额外建表。

还有个非常容易踩的坑——Domino人员文档的“姓名”字段格式。拿到的FullName往往是CN=张三/O=某某银行这种带DN前缀的格式,如果直接塞进MySQL的用户姓名字段,下游系统看到一长串CN=会直接报错。同步前必须做清洗,把CN=/O=之类的标识去掉。还有InternetAddressMailAddress可能不一致,要提前和业务确认到底以哪个字段为准。这类字段语义层面的坑,往往比技术本身更费时间。

3. Windows上必须先停服务才能打开Domino Server的来龙去脉

3.1 场景复盘:提示信息到底在说什么

热搜里那句“在services里面停止domino server服务,才能打开桌面的domino server”,说的是一个很典型的Windows部署场景:Domino Server被注册成了Windows服务(例如服务名“HCL Domino Server”),但同时又有人习惯在桌面登录时双击启动Domino控制台(桌面端的domino.exe)。如果你在Windows服务还在运行时去双击桌面上的Domino图标,通常会出现一个提示,大意是检测到另一个Domino Server实例在运行,无法重复启动。这个提示让很多刚接手的人抓瞎:明明“服务”里显示正在运行,为什么桌面端打不开?

3.2 根因:服务进程和桌面进程抢同一份配置

根本原因在于,Windows服务模式下,Domino Server进程(nserver.exe)已经加载了该服务器的数据目录和notes.ini,并占用了对应的端口(1352是Notes客户端通信端口,80/443是HTTP端口等)。桌面启动的Domino Server本质上也是nserver.exe,加载同一个数据目录时,会拿同一份notes.ini和同一组数据库文件。同一份数据目录被两个进程同时打开,会导致数据库损坏、日志写入错乱、端口冲突。所以Domino设计上就用一个“单实例锁”来避免这种情况——检测到服务已经在跑,桌面端启动就被拒绝。这不是软件bug,而是一种保护机制。

3.3 正确的启动与停止顺序

理解了原理,操作就很简单了:要打开桌面端的Domino控制台,先到Windows服务管理器中找到对应的Domino服务(注意看清服务器名称,有的人服务器名是“Domino/Server1”,服务显示名可能不同),右键停止;服务完全停止后,再去双击桌面图标启动桌面端。反过来,如果你想回到Windows服务方式运行,先关掉桌面端控制台,再启动服务。

这里有个细节:服务停止不是点了“停止”就立刻完成,Domino要几百兆数据在内存里,优雅关闭需要时间,可以通过控制台输出或者nserver -c确认真正退出。我以前吃过亏,在服务还显示“正在停止”时就急着启动桌面端,结果两个进程短暂并存,日志文件写出了乱码。稳妥的操作是停止服务后等待10秒以上,再打开桌面端。

3.4 开发机和服务器的不同管法

如果这台机器是正式生产服务器,我强烈建议全程用Windows服务方式运行,不要去双击桌面图标。原因有几点:Windows服务可以在服务器开机后无登录状态下自动拉起,服务器重启后Domino能自己恢复;服务方式支持用Windows服务管理器的“重启”操作快速恢复;服务跑在Session 0隔离环境里,不占用交互桌面的资源。而在开发机上,为了方便看控制台日志、调试代理,我更推荐用桌面端直接跑。所以最佳实践是:开发机用桌面端、生产机用Windows服务,两边不要混着来。如果只有一台机器,那就严格记住“要开桌面先停服务”这个顺序,并且要养成通过tell命令优雅关闭的习惯,不要直接结束进程。

4. Domino开发绕不开的四个底层机制

4.1 表单(Form)、视图(View)、代理(Agent)三元组

Domino应用最基础的开发模式,就是表单、视图、代理这三件套。表单定义数据的录入和展示界面,视图是数据的分类和列表展示(相当于SQL查询+结果集的变身),代理是实现业务逻辑的代码容器。一个典型OA应用长这样:用户通过表单填单,保存后生成一份文档;文档根据某些字段(如部门、审批状态)被分类进不同的视图;某个视图触发定时代理,把满足条件的文档推送给相关人员或写入外部系统。理解这三者的关系,就理解了Domino90%的应用形态。

4.2 ACL与身份认证:权限问题为什么难排查

Domino的权限体系分两层。第一层是数据库ACL(Access Control List),决定某个用户(或群组)对这个数据库能做什么——不能访问、存放者、作者、编辑者、设计者、管理者这六个级别。第二层是文档级权限,靠表单里的 “Readers” 和 “Authors” 字段控制哪些人能读、哪些人能改成某篇文档。真正排查权限问题时,往往要同时看ACL和文档字段两层,而且群组嵌套让关系变得更加复杂。一个用户看得到库名但打不开视图,通常先查ACL是否包含该用户或其所在的群组;如果打开视图了但看不到某些文档,就要看视图的“读者”公式和文档上的Readers字段是否一致。这套机制虽然安全做得细,但也要求在开发初期就规划好权限矩阵,否则后期靠一个字段一个字段地补,非常痛苦。

4.3 复制机制:离线协同的双刃剑

Domino的应用被设计为可以由多台服务器相互复制数据。复制让分支机构在断网时也能继续录单,网络恢复后再同步过去。但复制也带来了“复制冲突”——同一份文档在两处被同时修改,复制时会各自生成冲突文档。大多数冲突可以通过“按文档复制冲突解决策略”自动处理,比如最后修改者胜出;但如果你业务上需要保存双方修改,就必须设计“合并冲突”的逻辑。我记得有次给一个外勤报表做离线录入,没有设计好合并策略,业务人员在外地改完上报,总部这边也同时改了评审意见,结果评审意见被覆盖了一部分。从那以后,涉及双写场景的文档,我都会有意识的增加按字段合并的冲突处理逻辑,而不是依赖默认策略。

4.4 Formula、LotusScript、Java和XPages,到底学哪个

很多刚接触Domino的人会被这门平台的“多语言”吓到:表单公式、LotusScript、Java代理、XPages、SSJS(服务端JavaScript),到底学哪个?我的建议是分优先级:表单公式要会,因为很多视图选择和校验逻辑都写在其中;LotusScript适合处理业务逻辑相对简单的代理,代码量少、上手快,但不擅长与外部系统打交道;Java代理是我做系统集成的主力,能访问第三方数据库、能调HTTP接口、能处理复杂的数据清洗;XPages属于Web开发层,适合做较新的浏览器交互界面,但如果团队没有前端基础,维护成本偏高。老实说,对于集成类需求,学会Java代理基本能应付绝大部分场景。

5. 干Domino这些年,印象最深的四个坑

5.1 在生产库上直接改设计并立即刷新,差点把流程库改崩

早期我不懂事,直接在生产的names.nsf(通讯录)或者核心流程库上打开设计器,改了一个表单的字段结构,保存后点了“刷新设计”。结果所有正在操作这个表单的用户瞬间开始报错,因为客户端里的表单设计已经变了,而他们的界面还停留在旧版本,提交时字段校验对不上。后来我的铁律是:开发环境改设计,测试环境验证,生产环境只做“替换设计”并选择“保留ID”。而且设计变更尽量安排在非工作时间,提前通知用户说“这个时间点别提交单据”。这个教训说起来简单,但很多刚入门的人会重复踩。

5.2 视图里用@Now,性能直接掉到地板

Domino的视图索引是惰性刷新的,如果视图列公式里用了@Now@Today,等于告诉操作系统“每次刷新都要重算索引”,当数据量大时,视图打开慢到让人怀疑人生。正确做法是,把日期作为普通字段存在文档里,用视图的选择公式做日期范围过滤,需要显示“今天”这种动态值时,在表单里生成一个“查询日期”字段,或者只在代理里用@Now,而不是在视图列里直接调用。这个坑几乎每个Domino开发者都会遇到,属于性能优化里的头号问题。

5.3 定时代理连接MySQL不释放,把生产库拖死

有段时间我写了一个定时代理,每5分钟跑一次,把业务单据同步到MySQL。代理写得比较随意,每次跑都新建连接,正常情况下没什么问题。但有一次MySQL临时重启了,代理连接失败后没有回收连接,连接池里堆积了大量失效连接,加上Domino代理本身的内存周期,服务器负载直接飙高。后来我在Java代理里加了 try-with-resources 来确保连接关闭,同时增加了连接失败的重试计数,连续失败3次就发邮件告警而不是一直重试。这个经验也适用于所有和外部系统打交道的Domino代理——你写的代码不仅是在“跑业务”,也是在保护Domino主进程的稳定性。

5.4 邮件发得慢,最后查出来是DNS反向解析在作怪

还有个特别隐蔽的问题:Domino发邮件到外部互联网邮箱总是很慢,有的邮件需要一两分钟才出去。排查了很久,最后发现是服务器在做反向DNS解析——Domino在连接外部SMTP服务器时,会对目标IP做PTR记录查询,如果网络环境里反解析超时,连接建立就变慢。解决方案是在notes.ini里调整SMTP客户端的超时参数,或者让网络团队确保DNS服务器能快速响应反解析请求。这种问题不碰一次很难想到,但只要遇到一次,你以后排查邮件类问题就会多一个方向。

6. 最后再分享一点工具选择和团队协作的建议

根据我个人的经验,Domino项目能不能做好,很多时候不取决于技术深度,而取决于有没有把“配置、代码、数据”这三样东西分开管理。设计元素(表单、视图)用Domino设计器自带的DXL导出到Git做版本管理;代理代码用Java写在外部文件里,通过脚本导入,这样可以做code review;names.nsf这种系统库不要随便给设计者权限,要控制变更范围。团队里最好有一个人专门负责构建和发布流程,哪怕是“手工替换设计+检查服务器日志”这种半自动流程,也比所有人都有生产库设计权限要安全得多。

还有个小技巧,Windows服务器上如果桌面端和服务端混用,可以在桌面上建一个批处理命令,一键完成“停止服务并启动桌面端”的操作:

net stop "HCL Domino Server" timeout /t 10 "C:\Program Files\HCL\Domino\desktop\nserver.exe"

反过来,从桌面切换到服务模式就用net start "HCL Domino Server"。每次切换都先确认进程真正退出,再操作下一步,能省掉很多奇怪的故障排查时间。这些经验说到底都是“多动手、多踩坑、多总结”换来的,希望这篇文章能帮你在Domino开发这条路上少走几段弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询