外部函数介绍
为了能够在创建和使用自定义 DMSQL 程序时,使用其他语言实现的接口,DM8 提供了C、JAVA 外部函数,这样即使外部函数在执行中出现了任何问题,都不会影响到服务器的正常执行。
无论是 C 外部函数还是 JAVA 外部函数,都需要将动态库或 jar 包上传到服务器端或在服务器端编译生成动态库或 jar 包,系统管理员应对动态库和 jar 包进行严格审查,以防止外部函数中包含病毒或恶意代码,引发安全问题。为了保证数据库的安全性和灵活性,DM 提供了 ini 参数 ENABLE_EXTERNAL_CALL 来开关外部函数功能,默认情况下,数据库会关闭外部函数的创建和执行功能。 需要注意的是,DM 不支持 C 或 JAVA 外部函数存放在 ASM 文件系统上的调用。
更多的介绍请查看《DM8_SQL语言使用手册.pdf》,文档在数据库安装目录的doc目录下。
执行流程
JAVA 外部函数的执行都通过代理 dmagent 工具进行,为了执行 JAVA 外部函数,需要先启动 dmagent 服务。
dmagent 执行程序在 DM8 安装目录的 tool/dmagent 子目录下,其使用说明文档可参看该目录下的《readme》文档。
当用户调用 JAVA 外部函数时,服务器操作步骤如下:首先,确定调用(外部函数使用 的)jar 包及函数;然后,通知代理进程工作。代理进程装载指定的 jar 包,并在函数执 行后将结果返回给服务器。
需要注意的是,进行 JAVA 外部函数调用应保证当前用户可以运行 JAVA 命令,否则会导致调用失败。
编写程序
1. 配置数据库参数
DM 提供了 ini 参数 ENABLE_EXTERNAL_CALL 来开关外部函数功能,默认情况下,数据库会关闭外部函数的创建和执行功能。所以需要进行开启
-- 1. 查询 如果为参数为0 则执行下面的语句
select * from v$dm_ini where "V$DM_INI".PARA_NAME = 'ENABLE_EXTERNAL_CALL'
-- 2. 开启参数
sp_set_para_value(2,'ENABLE_EXTERNAL_CALL',1);
-- 3. 重启数据库
2. 编写java程序
- 编写测试程序并打包。
package com.dameng.externfunction;
public class test {
static int num = 0;
public static int testAdd(int a, int b) {
System.out.println("a="+a+",b="+b);
return a + b;
}
public static String testStr(String str) {
return str + " hello";
}
public static int testStatic(String str) {
System.out.println("testStatic"+1111);
num++;
return num;
}
public static int testError(String str) {
//int a = 1/0;
return num;
}
public static String testa(String args) throws Exception{
return args+"_aa";
}
}
- 将java_external_function.jar上传到指定dmdbms/bin/external_jar目录,同时注意jar工具的用户以及权限
[dmdba@VM-24-16-centos ~]$ cd /opt/dmdbms/bin/external_jar/
[dmdba@VM-24-16-centos external_jar]$ ll
-rw-r--r-- 1 dmdba dinstall 3640552 5月 10 14:33 java_external_function.jar
[dmdba@VM-24-16-centos external_jar]$ chown dmdba:dinstall java_external_function.jar
3. 配置agent服务
- 配置agent服务参数
[dmdba@VM-24-16-centos dmagent]$ cd /opt/dmdbms/tool/dmagent
[dmdba@VM-24-16-centos dmagent]$ vim agent.ini
## ap_enable 设置为true则启用外部函数的代理功能能,使用外部函数功能时dmagent 配置文件中ap_port要和数据库配置文件dm.ini中的EXTERNAL_JFUN_PORT 保持一致,配置文件内容如下:
#ap
ap_enable = true #whether enable ap plugin
ap_port = 6363 #ap listen tcp/ip port, , range[1~65535]
- 启动agent服务
-- 这里演示采用前台启动的方式,没有问题的话可启动后台服务
[root@VM-24-16-centos dmagent] ./start.sh ./agent.ini
注意事项:agent服务默认会连接Dem服务,如果没有关闭Dem连接的话,启动会很慢同时报连接错误的提示。知道出现 system is readly 则表明启动成功。如何关闭Dem的连接请前往附录查看。
4. 创建外部函数
-- 注意 EXTERNAL的值一定要用绝对路径 不要使用相对路径
-- 创建的用户需拥有DBA权限或者具有 CREATE FUNCTION 数据库权限,在达梦管理工具中创建外部函数,语句如下:
CREATE OR REPLACE FUNCTION "TTCH".testa(a varchar)
RETURN varchar
EXTERNAL '/opt/dmdbms/bin/external_jar/java_external_function.jar'
"com.dameng.externfunction.test.testa" USING java;
-- 然后正常调用即可
select testa('aa');
Q&A
1. 关闭Dem连接(重要)
使用agent服务用来支撑java外部函数的调用,并不需要与Dem通信的这个功能,关闭方法如下:修改一下参数
[dmdba@VM-24-16-centos dmagent]$ cd /opt/dmdbms/tool/dmagent
[dmdba@VM-24-16-centos dmagent]$ vim agent.ini
service_enable = false #whether enable service plugin
gather_enable = false #whether enable gather plugin
upgrade_enable = false #whether enable upgrade plugin
2. 全局变量的问题 (重要)
本次演示的java代码中 static int num = 0;变量,是数据库的所有会话的共享变量,会话间没有做隔离。可以调用testStatic方法做测试。一定要注意这个
3. INI参数文件错误
Linux的DM8环境下jar包路径分隔符若为 “\” 或者路径不对,外部函数编译不会报错,调用则识别不到jar包,报以下错误:
4. 没有创建函数权限
未修改配置文件 ENABLE_EXTERNAL_CALL=1,则无权限创建外部函数,报以下错误:
5. JAVA外部函数与DMAgent消息通信失败
外部函数返回类型和jar包函数返回类型不一致,导致调用外部函数报以下错:
6. 对象[xxx]处于无效状态
外部函数返回类型使用CLOB导致,导致编译有错误,调用外部函数报以下错误:
7. 外部函数执行失败
调用外部函数执行失败,查看dmagent日志,报jdk版本过低的错误,是数据库服务器的jdk版本低于jar包的jdk版本导致,通过升级数据库服务器jdk版本或者降低jar包jdk版本可解决。