整个过程的核心是 Oracle JVM (Java Virtual Machine),它内嵌在 Oracle 数据库中。

下面我将分步详细解释整个过程,从环境准备到具体调用,并附上完整的示例。
核心概念
- Oracle JVM: 数据库中一个完整的 Java 运行时环境,你需要先在数据库中启用它。
loadjava实用工具: 一个命令行工具,用于将 Java 类文件(.class)或 JAR 文件加载到 Oracle 数据库中,并将其存储为数据库对象。CREATE AND RESOLVE JAVA SOURCE: 也可以直接在 SQL*Plus 或其他工具中编写 Java 源代码,并让数据库编译它。CREATE JAVA: 用于加载已编译的 Java 类。CREATE OR REPLACE AND COMPILE JAVA SOURCE: 用于创建或替换 Java 源代码并编译它。CREATE PROCEDURE/FUNCTION: 这是关键一步,它创建一个数据库的存储过程或函数,并将其“映射”到一个静态的 Java 方法上,当你在 SQL 或 PL/SQL 中调用这个存储过程时,实际上是在执行 Java 方法。
详细步骤与示例
假设我们要实现一个简单的功能:在数据库中调用一个 Java 方法,该方法接收一个字符串,然后将它转换为大写并返回。
第 1 步:准备 Java 环境
确保你的 Oracle 数据库已经启用了 JVM,安装数据库时会默认安装,但可能并未启用,你可以使用以下 SQL 查询来检查:
-- 查看是否安装了 JVM SELECT owner, object_name, object_type, status FROM all_objects WHERE object_type LIKE '%JAVA%' AND object_name = 'JAVAVM';
JAVAVM 对象存在且状态为 VALID,则 JVM 已安装,如果未启用,需要以 SYS 用户身份运行 dbms_java 包来设置(具体步骤请参考 Oracle 官方文档,因为这涉及到数据库安全配置)。

第 2 步:编写 Java 代码
创建一个 Java 类,它将包含我们想要调用的方法。注意:
- 方法必须是
public static的。 - 参数和返回值的类型必须是 Java 原始类型或 Oracle 可以自动映射的类型(如
String,java.sql.Date,java.math.BigDecimal等)。
StringUtils.java
package com.example.utils;
public class StringUtils {
/**
* 将输入的字符串转换为大写
* @param input 输入字符串
* @return 转换后的大写字符串
*/
public static String toUpperCase(String input) {
if (input == null) {
return null;
}
System.out.println("Java 方法被调用,输入是: " + input);
return input.toUpperCase();
}
/**
* 一个无返回值的方法,用于打印信息
* @param message 要打印的消息
*/
public static void printMessage(String message) {
System.out.println("[来自 Java 的消息]: " + message);
}
}
第 3 步:将 Java 代码加载到数据库
你有两种主要方式可以将代码加载到数据库中。
方式 A:使用 loadjava 命令行工具 (推荐用于 JAR 文件)

-
编译 Java 代码:
javac -d . StringUtils.java
这会生成
com/example/utils/StringUtils.class文件。 -
打包成 JAR (可选,但推荐):
jar -cvf StringUtils.jar com/
-
使用
loadjava上传: 你需要知道你的数据库 TNS 名称(或主机、端口、SID/SERVICE_NAME)以及一个有权创建 Java 对象的用户(如SCOTT)。loadjava -user scott/tiger@orcl -resolve StringUtils.jar
-user scott/tiger@orcl: 数据库用户名/密码@连接字符串。-resolve: 加载后立即解析(编译)Java 代码,如果省略,代码只是加载,需要后续手动编译。
方式 B:使用 SQL 语句 (适合单个简单类)
直接在 SQL*Plus 或类似工具中执行:
-- 创建或替换 Java 源代码并编译
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED 'StringUtils' AS
package com.example.utils;
public class StringUtils {
public static String toUpperCase(String input) {
if (input == null) {
return null;
}
System.out.println("Java 方法被调用,输入是: " + input);
return input.toUpperCase();
}
public static void printMessage(String message) {
System.out.println("[来自 Java 的消息]: " + message);
}
};
/
是执行 SQL 语句的命令。
加载完成后,你可以查询 USER_OBJECTS 来验证:
SELECT object_name, object_type, status FROM user_objects WHERE object_type = 'JAVA CLASS';
你应该能看到 STRINGUTILS 对象,并且状态为 VALID。
第 4 步:创建 PL/SQL 包装器(调用 Java 方法)
这是最关键的一步,我们需要创建一个 PL/SQL 存储过程或函数,让它指向我们刚才加载的 Java 方法。
创建一个有返回值的函数 (映射 toUpperCase)
CREATE OR REPLACE FUNCTION java_to_uppercase(p_input IN VARCHAR2) RETURN VARCHAR2 AS LANGUAGE JAVA NAME 'com.example.utils.StringUtils.toUpperCase(java.lang.String) return java.lang.String'; /
AS LANGUAGE JAVA: 声明这是一个 Java 语言调用。NAME '...': 这是 Java 方法的完整签名,格式为'包名.类名.方法名(参数列表) return 返回类型'。- 注意:在 SQL/PL/SQL 中,
VARCHAR2类型会自动映射到 Java 的java.lang.String。
创建一个无返回值的过程 (映射 printMessage)
CREATE OR REPLACE PROCEDURE java_print_message(p_message IN VARCHAR2) AS LANGUAGE JAVA NAME 'com.example.utils.StringUtils.printMessage(java.lang.String)'; /
- 对于
PROCEDURE(过程),没有RETURN部分。
第 5 步:调用和测试
你可以像调用普通的 PL/SQL 过程和函数一样调用它们了。
调用函数
SET SERVEROUTPUT ON; -- 确保 PL/SQL 的输出可以显示
DECLARE
v_result VARCHAR2(100);
BEGIN
v_result := java_to_uppercase('Hello from Java!');
DBMS_OUTPUT.PUT_LINE('PL/SQL 收到的结果是: ' || v_result);
END;
/
预期输出:
Java 方法被调用,输入是: Hello from Java!
PL/SQL 收到的结果是: HELLO FROM JAVA!
调用过程
BEGIN
java_print_message('This is a test message from PL/SQL.');
END;
/
预期输出:
[来自 Java 的消息]: This is a test message from PL/SQL.
重要注意事项和最佳实践
-
性能:
- 首次调用有开销: JVM 需要被“预热”,第一次调用 Java 代码会比后续调用慢。
- 避免频繁调用: 对于非常简单的、单行的操作(如字符串拼接、简单算术),直接使用 PL/SQL 内置函数性能更高,将 Java 用于复杂的算法、数据处理或外部集成。
-
权限:
- 调用 Java 存储过程的用户需要
EXECUTE权限。 - Java 代码需要访问文件系统、网络等,你需要使用
DBMS_JAVA包的GRANT_PERMISSION方法来授予权限,允许读取文件:BEGIN DBMS_JAVA.GRANT_PERMISSION('SCOTT', 'SYS:java.io.FilePermission', '<<ALL FILES>>', 'read'); END; /
- 调用 Java 存储过程的用户需要
-
错误处理:
- Java 代码抛出异常,PL/SQL 调用会失败,你可以使用
PRAGMA EXCEPTION_INIT或EXCEPTION块来捕获和处理这些错误。 - 你可以在 Java 代码中使用
throw new SQLException("错误信息", "错误代码");来将 Java 异常转换为 PL/SQL 可识别的数据库错误。
- Java 代码抛出异常,PL/SQL 调用会失败,你可以使用
-
调试:
- 调试 Java 存储过程比较困难,一个常用的技巧是使用
System.out.println()将调试信息打印到标准输出,然后在 PL/SQL 中使用DBMS_OUTPUT.PUT_LINE来捕获和显示这些信息。 - 对于更复杂的调试,Oracle 提供了
jdb(Java Debugger) 的服务器模式,但这需要更复杂的配置。
- 调试 Java 存储过程比较困难,一个常用的技巧是使用
-
部署:
- 对于生产环境,推荐将所有相关的 Java 类打包成一个 JAR 文件,然后使用
loadjava工具一次性部署,这样更易于管理和版本控制。
- 对于生产环境,推荐将所有相关的 Java 类打包成一个 JAR 文件,然后使用
通过以上步骤,你就可以成功地在 Oracle 存储过程中调用 Java 代码,极大地扩展了数据库应用的功能和灵活性。
