达梦数据库-学习-45-JAVA外部函数
目录
一、环境信息
| 名称 | 值 |
| 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外部函数,用C外部函数的少之又少,再写一篇记录一下,学无止境。
三、C外部函数链接
C外部函数链接可以参考一下之前的博客。
| 序号 | 链接 |
| 1 | 《达梦数据库-学习-21-C 外部函数》 |
四、介绍
1、语法树
CREATE [OR REPLACE] FUNCTION [IF NOT EXISTS] [<模式名>.]<函数名>[(<外部函数参数列表>)] RETURN <返回值类型> EXTERNAL '<jar 包路径>' [AND] <引用的 JAVA 函数名>[(<JAVA 函数参数列表>)] USING JAVA; <外部函数参数列表>::=<外部函数参数声明> {,<外部函数参数声明>} <外部函数参数声明>::=<外部函数参数名> [<外部函数参数模式>]<外部函数参数类型> <JAVA 函数参数列表>::=<JAVA 函数参数声明> {,<JAVA 函数参数声明>} <JAVA 函数参数声明>::=<JAVA 函数参数类型> 2、参数
| 名称 | 描述 |
| <函数名> | 被创建的 JAVA 外部函数的名字; |
| <模式名> | 被创建的 JAVA 外部函数所属模式的名字,缺省为当前模式名; |
| <外部函数参数列表> | JAVA 外部函数参数信息; |
| <外部函数参数模式> | 可设置为 IN、OUT 或 IN OUT(OUT IN),缺省为 IN 类型。参数类型、个数都应和 jar 包里的一致; |
| <外部函数参数类型> | 目前支持的函数参数类型:int、字符串(char、varchar、varchar2)、bigint、double/float/binary_float、binary/varbinary、clob、blob,分别对应 java 类型:int、string、 long、double、byte[]、string、byte[]; |
| <返回值类型> | 必须 jar 包里定义的一致; |
| <jar 包路径> | 用户按照 JAVA 语言格式编写的源码生成的 jar 包,及其依赖的 jar包所在的相对路径或绝对路径; |
| <引用的 JAVA 函数名> | <引用的 JAVA 函数名> 指明<函数名>在<jar 包路径>中对应的 JAVA 函数名,函数调用通过 JAVA 反射实现,建议调用函数访问限定符为 public,另外,所属类须不含构造函数或包含无参的构造函数。若<函数名>包含包名,则包名(或.包名)与类名的分隔符要用.或/。而类与方法的分隔符要用.。若不指定<引用函数名>,则后续使用 JAVA 外部函数时会报错。一个正确的 JAVA 函数名示例如下:……EXTERNAL '/data/sda/test.jar' "com.test.package1.test.pass(java.lang.String,java.lang.String[])" USING JAVA;; |
| <JAVA 函数参数列表> | 用于指定 JAVA 函数的参数列表。缺省情况下,系统自动定位参数。只有未指定<外部函数参数模式>或<外部函数参数模式>中所有参数模式均为IN时,<JAVA 函数参数列表>才可缺省; <JAVA 函数参数声明>由一个或多个<JAVA 函数参数类型>组成。<JAVA 函数参数类型>书写时必须包括 JAVA 类的完整名称。例如:……EXTERNAL '/data/sda/test.jar' "com.test.package1.test.pass(java.lang.String,java.lang.String[])" USING JAVA;。 |
3、注意点
| 序号 | 描述 |
| 1 | 当<引用的 JAVA 函数名>[(<JAVA 函数参数列表>)]的长度超过 128 个字节并且不超过 32767 个字节时,不能使用双引号,需要改用单引号括起来,并且需要指定 AND 关键字。例如:EXTERNAL '/data/sda/test.jar' AND 'com.test.package1.test.pass(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String)' USING JAVA; |
| 2 | 三权分立下,仅允许拥有 DBA 权限的用户创建外部函数;四权分立下,仅允许拥有 DB_OBJECT_ADMIN 权限的用户创建外部函数; |
| 3 | 创建或执行外部函数需要设置 INI 参数 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 restart3、生成并安装 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、agent.ini配置
[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/dmagentagent.ini配置的6363端口需和dm.ini中的EXTERNAL_JFUN_PORT参数一致。
[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.java8、打Jar包
[dmdba@rhel709 DmJar]$ jar cvf test.jar com/test/package1/test.class 已添加清单 正在添加: com/test/package1/test.class(输入 = 526) (输出 = 323)(压缩了 38%)9、拷贝jar包
cp /home/dmdba/DmJar/test.jar /dm/dmdbms/tool/dmagent/resources/ap/一定要放到这个目录下,不然在执行时会提示如下报错:
SQL> select MY_chr('abc'); [-7094]:外部函数共享库加载失败,错误详情[invalid jar path, jar should under resources/ap directory]. 已用时间: 2.153(毫秒). 执行号:0.10、创建外部函数
这里建议大家设置相对路径,这样可以避免在集群模式下,多节点目录不一致导致找不到JAR包的问题。
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;11、验证
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.