环境
| 名称 | 值 |
|---|---|
| CPU | 12th Gen Intel(R) Core(TM) i7-12700H |
| 操作系统 | CentOS Linux release 7.9.2009 (Core) |
| 内存 | 7G |
| 逻辑核数 | 8 |
| DM 版本 | DM Database Server 64 V8 DB Version: 0x7000d 03134284368-20250917-293539-20149 Msg Version: 44 Gsu level(5) cnt: 0 |
最近有个需求要在达梦数据库里跑一些 Java 逻辑,于是折腾了一下它的 Java 外部函数。整个过程不算复杂,但有几个地方不注意就会报错,顺手记下来。
大概流程
创建外部函数的基本语法是:
CREATE [OR REPLACE] FUNCTION [IF NOT EXISTS] [<模式名>.]<函数名>[(<外部函数参数列表>)] RETURN <返回值类型> EXTERNAL '<jar 包路径>' [AND] <引用的 JAVA 函数名>[(<JAVA 函数参数列表>)] USING JAVA;
参数类型映射大致是这样:
int→intchar/varchar/varchar2→Stringbigint→longdouble/float/binary_float→doublebinary/varbinary→byte[]clob→Stringblob→byte[]
调用函数通过 Java 反射进行,所以方法最好声明为 public,所属类要有无参构造。<引用的 JAVA 函数名> 里包名和类名用 . 或 / 分隔,类与方法之间用 .。比如:
EXTERNAL '/data/sda/test.jar' "com.test.package1.test.pass(java.lang.String,java.lang.String[])" USING JAVA
如果引用函数名长度超过 128 字节,就得改用单引号括起来,并且加上 AND 关键字:
EXTERNAL '/data/sda/test.jar' AND 'com.test.package1.test.pass(java.lang.String, java.lang.String, ...)' USING JAVA
一些限制要注意:三权分立下只有 DBA 能建,四权分立下得有 DB_OBJECT_ADMIN 权限;参数 ENABLE_EXTERNAL_CALL 必须设为 1。
动手配置
1. 开启参数
[root@rhel709:/root]# cat /dmdata/DAMENG2/dm.ini |grep ENABLE_EXTERNAL_CALL
ENABLE_EXTERNAL_CALL = 1 #Whether permit external call
直接改文件还是不太放心,我习惯用存储过程设置:
SQL> SP_SET_PARA_VALUE(2,'ENABLE_EXTERNAL_CALL',1);
DMSQL 过程已成功完成
已用时间:9.553(毫秒). 执行号:1002.
2. 重启数据库
[dmdba@rhel709 bin]$ ./DmServiceDM restart
3. 生成 service.key
[dmdba@rhel709 dmagent]$ ./start.sh INSTALL_SERVICE_KEY 999999
tip: if using the deployment feature, it is recommended to start dmagent with the '-d' parameter.
Agent-V7.6.1.34685-2025.03.26-DEV Key file: "/dm/dmdbms/tool/dmagent/service.key" generated.
4. 配置 dmagent
agent.ini 里把 AP 插件打开,端口和数据库参数一致:
[dmdba@rhel709 dmagent]$ cat agent.ini |grep -E 'ap_enable|ap_port'
ap_enable = true #whether enable ap plugin
ap_port = 6363 #ap listen tcp/ip port, range[1~65535]
[dmdba@rhel709 dmagent]$ pwd
/dm/dmdbms/tool/dmagent
[dmdba@rhel709 dmagent]$ cat /dmdata/DAMENG2/dm.ini |grep EXTERNAL_JFUN_PORT
EXTERNAL_JFUN_PORT = 6363 #DmAgent port for external java fun.
5. 启动 dmagent
[dmdba@rhel709 dmagent]$ ./start.sh -d agent.ini
Starting dmagent.....
dmagent(pid: 16039) started successfully.
6. 写测试代码
搞个最简单的加法与字符串拼接:
[dmdba@rhel709 DmJar]$ cat test.java
package com.test.package1;
public class test {
public static int testAdd(int a, int b) {
return a + b;
}
public static String testStr(String str) {
return str + " hello";
}
}
7. 编译打包
[dmdba@rhel709 DmJar]$ javac -d . test.java
[dmdba@rhel709 DmJar]$ jar cvf test.jar com/test/package1/test.class
已添加清单
正在添加:com/test/package1/test.class(输入 = 526) (输出 = 323)(压缩了 38%)
8. 拷贝 jar 到指定目录
cp /home/dmdba/DmJar/test.jar /dm/dmdbms/tool/dmagent/resources/ap/
这一步是关键,jar 包必须放在 resources/ap 下面,否则创建函数时会报:
SQL> select MY_chr('abc');
[-7094]:外部函数共享库加载失败,错误详情 [invalid jar path, jar should under resources/ap directory].
已用时间:2.153(毫秒). 执行号:0.
9. 创建外部函数
建议用相对路径,这样集群多节点时不用操心目录差异:
CREATE OR REPLACE FUNCTION MY_INT(a int, b int) RETURN int EXTERNAL 'resources/ap/test.jar' "com.test.package1.test.testAdd" USING java;
CREATE OR REPLACE FUNCTION MY_chr(s varchar) RETURN varchar EXTERNAL 'resources/ap/test.jar' "com.test.package1.test.testStr" USING java;
10. 试一下
SQL> select MY_INT(1,2);
行号 MY_INT(1,2)
---------- -----------
1 3
已用时间:0.942(毫秒). 执行号:4505.
SQL> select MY_chr('abc');
行号 MY_CHR('abc')
---------- -------------
1 abc hello
已用时间:1.080(毫秒). 执行号:4506.
功能正常。整体来看达梦的 Java 外部函数用起来还算顺畅,主要是提前配好 dmagent 和放对 jar 路径,基本就不会踩坑。

