一、外部函数概述:理解DM8外部函数的价值与应用场景
1.1 外部函数的核心概念
DM8(达梦数据库8)除了内置函数和PL/SQL自定义函数外,还提供了一种功能强大的扩展机制——外部函数。外部函数是指由用户使用C语言或JAVA语言编写,编译后以动态链接库或JAR包形式存在数据库外部,通过SQL语句调用的自定义函数。
外部函数与内置函数和存储过程函数相比,具有以下特点:
- 突破SQL语言表达能力限制,可调用操作系统API或第三方库。
- 适合处理复杂算法、加密解密、文件操作等场景。
- 支持C和JAVA两种主流开发语言,开发灵活度高。
1.2 外部函数的分类
DM8支持两类外部函数:
- C外部函数:以动态链接库(Linux下为.so文件,Windows下为.dll文件)形式存在,性能较高,适合对性能要求极高的场景。
- JAVA外部函数:以JAR包形式存在,依赖JVM环境,开发便捷,可复用大量第三方Java库。
1.3 外部函数的执行流程
外部函数从SQL调用到返回结果,经历加载库、参数转换、函数执行、结果回传等关键步骤。完整流程如下图所示:
二、C外部函数开发:从编写到部署的完整流程
2.1 创建C外部函数的语法
DM8创建C外部函数的基本语法如下:
CREATE [OR REPLACE] FUNCTION func_name[(parameter_list)]
RETURN return_type
AS LANGUAGE C
NAME 'lib_name.func_name_in_lib'
[PARAMETER STYLE GENERAL];
关键字说明:
- func_name:数据库中注册的函数名。
- parameter_list:参数列表,格式为 参数名 IN 数据类型。
- return_type:返回值数据类型。
- lib_name:动态链接库的名称(不含扩展名)。
- func_name_in_lib:库中实际导出的函数名。
2.2 编写C语言源文件
下面编写一个实现两个整数相加的C函数,作为外部函数示例。
#include <stdlib.h>
#include <string.h>
/* 简单加法函数 */
int my_add(int a, int b) {
return a + b;
}
/* 字符串反转函数 */
char* str_reverse(char* src) {
if (src == NULL) return NULL;
int len = strlen(src);
char* result = (char*)malloc(len + 1);
for (int i = 0; i < len; i++) {
result[i] = src[len - 1 - i];
}
result[len] = '\0';
return result;
}
2.3 编译生成动态链接库
将上述C源码保存为ext_func.c,分别在不同平台编译为动态链接库。
Linux平台编译命令:
gcc -fPIC -shared -o libext_func.so ext_func.c
Windows平台编译命令(使用MSVC):
cl /LD ext_func.c /Fe:ext_func.dll
编译完成后将动态库文件放置到DM8安装目录的bin文件夹下,或自定义路径。
2.4 配置dm.ini关键参数
要让DM8正确加载外部函数,需要修改dm.ini配置文件,主要参数如下:
# 是否启用外部函数
ENABLE_EXTERNAL_CALL = 1
# 外部函数库搜索路径,多个路径以冒号分隔(Linux)或分号分隔(Windows)
EXTERNAL_FUN_DIR = /dm8/bin
修改完成后重启DM8实例使配置生效。
2.5 创建并调用外部函数
使用DISQL工具登录数据库,创建外部函数:
-- 创建加法外部函数
CREATE OR REPLACE FUNCTION uf_add(a INT, b INT)
RETURN INT
AS LANGUAGE C
NAME 'ext_func.my_add'
PARAMETER STYLE GENERAL;
-- 创建字符串反转外部函数
CREATE OR REPLACE FUNCTION uf_str_reverse(src VARCHAR(100))
RETURN VARCHAR(100)
AS LANGUAGE C
NAME 'ext_func.str_reverse'
PARAMETER STYLE GENERAL;
调用外部函数进行验证:
SELECT uf_add(10, 20) AS sum_result;
SELECT uf_str_reverse('Hello DM8') AS reversed_str;
三、JAVA外部函数开发:基于JVM的函数扩展方案
3.1 JAVA外部函数环境准备
JAVA外部函数依赖JVM环境,配置步骤如下:
- 安装JDK 1.8及以上版本。
- 设置JAVA_HOME环境变量。
- 在dm.ini中配置JAVA相关参数:
ENABLE_EXTERNAL_CALL = 1
JAVA_JVM_PATH = /usr/lib/jvm/java-8-openjdk/lib/server/libjvm.so
3.2 编写Java类
编写Java类时,所有供外部调用的方法必须为public static。
package com.dm.ext;
public class ExtFuncDemo {
/* 加法运算 */
public static int javaAdd(int a, int b) {
return a + b;
}
/* 字符串拼接 */
public static String concatStr(String s1, String s2) {
return s1 + s2;
}
/* MD5加密 */
public static String md5Encrypt(String input) {
try {
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
byte[] array = md.digest(input.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte b : array) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (Exception e) {
return null;
}
}
}
3.3 编译打包JAR文件
编译Java源码并打包为JAR文件:
# 编译
javac -d build ExtFuncDemo.java
# 打包
jar cvf extfunc.jar -C build .
将生成的extfunc.jar文件放置到DM8安装目录的jar子目录下,或在dm.ini中配置:
EXTERNAL_JAR_DIR = /dm8/jar
3.4 创建JAVA外部函数
创建JAVA外部函数的语法稍有不同,使用LANGUAGE JAVA:
-- 创建加法函数
CREATE OR REPLACE FUNCTION uf_java_add(a INT, b INT)
RETURN INT
AS LANGUAGE JAVA
NAME 'com.dm.ext.ExtFuncDemo.javaAdd(int, int) return int';
-- 创建字符串拼接函数
CREATE OR REPLACE FUNCTION uf_concat(s1 VARCHAR(200), s2 VARCHAR(200))
RETURN VARCHAR(400)
AS LANGUAGE JAVA
NAME 'com.dm.ext.ExtFuncDemo.concatStr(java.lang.String, java.lang.String) return java.lang.String';
-- 创建MD5加密函数
CREATE OR REPLACE FUNCTION uf_md5(input VARCHAR(500))
RETURN VARCHAR(64)
AS LANGUAGE JAVA
NAME 'com.dm.ext.ExtFuncDemo.md5Encrypt(java.lang.String) return java.lang.String';
3.5 调用JAVA外部函数验证
调用刚创建的JAVA外部函数:
SELECT uf_java_add(100, 200) AS add_result;
SELECT uf_concat('Hello ', 'DM8') AS concat_result;
SELECT uf_md5('admin123') AS md5_result;
四、外部函数管理:日常维护与最佳实践
4.1 查看外部函数信息
通过系统视图查看已创建的外部函数:
-- 查看所有外部函数
SELECT * FROM ALL_ARGUMENTS WHERE OBJECT_NAME LIKE 'UF_%';
-- 查看函数定义
SELECT OBJECT_NAME, OBJECT_TYPE, STATUS
FROM ALL_OBJECTS
WHERE OBJECT_TYPE = 'FUNCTION';
4.2 修改与删除外部函数
DM8不直接支持ALTER FUNCTION修改外部函数体,需要先删除再创建:
-- 删除外部函数
DROP FUNCTION uf_add;
DROP FUNCTION uf_md5;
-- 重新创建
CREATE OR REPLACE FUNCTION uf_add(a INT, b INT)
RETURN INT
AS LANGUAGE C
NAME 'ext_func.my_add'
PARAMETER STYLE GENERAL;
4.3 外部函数调用限制
使用外部函数时需注意以下限制:
- 外部函数中不允许访问数据库对象。
- 外部函数的参数和返回值类型必须与C/JAVA函数严格对应。
- 避免在外部函数中使用全局变量或静态变量保存会话状态。
- 外部函数异常必须捕获,避免进程崩溃。
4.4 性能优化建议
外部函数优化要点如下:
五、典型应用场景:外部函数实战案例
5.1 数据加密场景
对敏感字段(如身份证号、手机号)进行加密存储时,可使用JAVA外部函数封装加密算法。
-- 创建AES加密外部函数(Java端实现)
CREATE OR REPLACE FUNCTION uf_aes_encrypt(plain_text VARCHAR(500), key_val VARCHAR(32))
RETURN VARCHAR(1000)
AS LANGUAGE JAVA
NAME 'com.dm.ext.CryptoUtil.aesEncrypt(java.lang.String, java.lang.String) return java.lang.String';
-- 在业务表中使用
UPDATE sys_user
SET id_card_encrypt = uf_aes_encrypt(id_card, 'dm8_secret_key_2024')
WHERE id_card IS NOT NULL;
-- 查询时解密
SELECT user_name, uf_aes_decrypt(id_card_encrypt, 'dm8_secret_key_2024') AS id_card
FROM sys_user
WHERE user_id = 1001;
5.2 复杂字符串处理场景
当SQL内置函数无法满足复杂字符串处理需求时,外部函数可以扩展能力。
-- 创建身份证校验外部函数
CREATE OR REPLACE FUNCTION uf_check_id_card(id_card VARCHAR(20))
RETURN INT
AS LANGUAGE C
NAME 'ext_func.check_id_card'
PARAMETER STYLE GENERAL;
-- 校验用户身份证有效性
SELECT user_name, id_card,
CASE WHEN uf_check_id_card(id_card) = 1 THEN '有效'
ELSE '无效' END AS check_result
FROM sys_user
WHERE id_card IS NOT NULL;
5.3 文件操作场景
通过C外部函数调用操作系统API,实现数据库对服务器文件的管理能力。
-- 创建文件读取外部函数
CREATE OR REPLACE FUNCTION uf_read_file(file_path VARCHAR(500))
RETURN CLOB
AS LANGUAGE C
NAME 'ext_func.read_file_content'
PARAMETER STYLE GENERAL;
-- 将日志文件内容写入数据库表
INSERT INTO log_archive(log_name, log_content)
SELECT 'app.log', uf_read_file('/dm8/log/app.log');
COMMIT;
5.4 调用第三方服务场景
借助JAVA外部函数,可调用HTTP接口或Web Service,实现数据集成。
-- 创建HTTP请求外部函数
CREATE OR REPLACE FUNCTION uf_http_get(url VARCHAR(1000))
RETURN CLOB
AS LANGUAGE JAVA
NAME 'com.dm.ext.HttpUtil.doGet(java.lang.String) return java.lang.String';
-- 实时查询汇率数据
SELECT uf_http_get('https://api.example.com/exchange?from=USD&to=CNY') AS rate_info
FROM DUAL;
外部函数作为DM8 SQL语言的重要扩展机制,为复杂数据处理提供了灵活的解决方案。在实际应用中,应平衡开发便利性与运行性能,根据业务特点选择合适的实现方式。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/qq_41840843/article/details/163574248




