杰瑞科技汇

Oracle存储过程如何调用Java方法?

核心概念:Oracle JVM

Oracle 数据库自带了一个完整的、与数据库集成的 JVM,这意味着你可以在数据库中:

Oracle存储过程如何调用Java方法?-图1
(图片来源网络,侵删)
  • 编译 Java 源代码CREATE AND REPLACE JAVA ... SOURCE ...
  • 加载 Java 类文件CREATE AND REPLACE JAVA ... RESOLVER ...
  • 在 SQL 或 PL/SQL 中调用 Java 方法:通过 CALL 语句或 CREATE OR REPLACE AND COMPILE JAVA SOURCE ... AS ... 后,定义一个 PL/SQL 外部过程来调用。

调用 Java 的两种主要方式

通常有两种主流方式来调用 Java:

  1. 通过 SQL 的 CALL 语句:这种方式最直接,适合简单的、无状态的 Java 方法调用,它不依赖于 PL/SQL 环境。
  2. 通过 PL/SQL 过程/函数:这是最常用、最灵活的方式,它允许你将 Java 方法封装成一个 PL/SQL 的接口,这样 PL/SQL 代码块、其他存储过程、触发器等都可以像调用普通 PL/SQL 过程一样调用它,这种方式也便于管理权限和错误处理。

我们将重点讲解第二种方式,因为它在实际应用中更为普遍。


详细步骤:通过 PL/SQL 调用 Java

整个过程可以分为以下几个步骤:

步骤 1:编写 Java 代码

你编写标准的 Java 代码,为了能被 PL/SQL 调用,Java 方法必须是 public static 的。

Oracle存储过程如何调用Java方法?-图2
(图片来源网络,侵删)

示例:HelloWorld.java

// 这个类将定义一个可以被 PL/SQL 调用的方法
public class HelloWorld {
    // PL/SQL 只能调用 public static 方法
    // 方法参数和返回值类型必须是 Java 基本类型或 Oracle 可以自动映射的类型
    public static String sayHello(String name) {
        return "Hello from Java, " + name + "!";
    }
    // 一个返回数字的示例
    public static int addNumbers(int a, int b) {
        return a + b;
    }
}

步骤 2:在数据库中创建 Java 类源代码

使用 CREATE AND JAVA SOURCE 语句将 Java 源代码加载到数据库中。

CREATE AND REPLACE JAVA SOURCE named "HelloWorld" AS
-- 将上面 Java 代码的完整内容粘贴到这里
-- 注意:不要包含 'public class HelloWorld' 这一行,因为 NAME 子句已经指定了类名
-- 但实际上,包含进去通常也没问题,数据库会处理。
-- 最佳实践是粘贴完整的源代码。
public class HelloWorld {
    public static String sayHello(String name) {
        return "Hello from Java, " + name + "!";
    }
    public static int addNumbers(int a, int b) {
        return a + b;
    }
};
/
  • CREATE AND REPLACE:如果类已存在,则替换它。
  • JAVA SOURCE named "HelloWorld":指定 Java 类的完全限定名(包名+类名),这里我们用了简单的类名。
  • AS ... ;:Java 源代码的开始和结束。
  • 在 SQL*Plus 或类似工具中,执行该语句。

步骤 3:编译 Java 类

使用 ALTER JAVA 语句来编译加载的 Java 源代码。

ALTER JAVA SOURCE "HelloWorld" COMPILE;
  • 如果编译成功,不会有任何输出。
  • 如果有编译错误,Oracle 会返回详细的错误信息,包括行号和错误原因。

步骤 4:创建 PL/SQL 外部过程(调用器)

这是连接 PL/SQL 和 Java 的关键桥梁,我们需要创建一个 PL/SQL 函数或过程,它内部会调用 LOADJAVA 工具生成的调用接口,或者更直接地,使用 CALL 语句。

Oracle存储过程如何调用Java方法?-图3
(图片来源网络,侵删)

最简单的方式是使用 JAVA 关键字和 CALL 语句。

示例:创建一个 PL/SQL 函数 call_java_say_hello

CREATE OR REPLACE FUNCTION call_java_say_hello(p_name IN VARCHAR2) 
RETURN VARCHAR2
AS LANGUAGE JAVA
NAME 'HelloWorld.sayHello(java.lang.String) return java.lang.String';
/

代码解析:

  • CREATE OR REPLACE FUNCTION ...:定义一个 PL/SQL 函数。
  • AS LANGUAGE JAVA:指定这是一个 Java 外部函数。
  • NAME '...':这是最核心的部分,它定义了 PL/SQL 和 Java 方法之间的映射关系。
    • HelloWorld.sayHello:要调用的 Java 类名和方法名。
    • (java.lang.String):Java 方法的参数类型,即使 String 是核心类型,也最好使用完全限定名 java.lang.String
    • return java.lang.String:Java 方法的返回值类型。

示例:创建一个 PL/SQL 函数 call_java_add_numbers

CREATE OR REPLACE FUNCTION call_java_add_numbers(p_a IN NUMBER, p_b IN NUMBER) 
RETURN NUMBER
AS LANGUAGE JAVA
NAME 'HelloWorld.addNumbers(int, int) return int';
/
  • 注意类型映射
    • VARCHAR2 (PL/SQL) <-> java.lang.String (Java)
    • NUMBER (PL/SQL) <-> java.lang.Number (Java) 或 int, double 等,对于整数,NUMBER 会自动映射到 intjava.lang.Integer
    • DATE (PL/SQL) <-> java.sql.Date (Java)
    • BLOB (PL/SQL) <-> java.sql.Blob (Java)

步骤 5:调用和测试

你可以像调用任何普通的 PL/SQL 函数一样调用它。

-- 测试 sayHello 函数
SELECT call_java_say_hello('PL/SQL Developer') AS greeting FROM DUAL;
-- 输出:
-- GREETING
-- ----------------------------------------
-- Hello from Java, PL/SQL Developer!
-- 测试 addNumbers 函数
SELECT call_java_add_numbers(10, 25) AS sum_result FROM DUAL;
-- 输出:
-- SUM_RESULT
-- ----------------
-- 35

高级示例:在 Java 中访问数据库

Java 代码最强大的地方在于它可以访问数据库,这需要使用 JDBC,在 Oracle JVM 中,有一个特殊的驱动类 oracle.jdbc.driver.OracleDriver,它允许 Java 代码直接连接到运行它的同一个数据库。

示例:DatabaseUtils.java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DatabaseUtils {
    // 这个方法会查询一个表并返回结果
    public static String getEmpNameFromId(int empId) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        String empName = "Not Found";
        try {
            // 1. 加载 JDBC 驱动
            // 注意:这是 Oracle JVM 内置的驱动,不需要额外的 jar 包
            Class.forName("oracle.jdbc.driver.OracleDriver");
            // 2. 获取数据库连接
            // "jdbc:default:connection" 是一个特殊的 URL,表示连接到当前数据库会话
            conn = DriverManager.getConnection("jdbc:default:connection", "", "");
            // 3. 创建语句
            stmt = conn.createStatement();
            String sql = "SELECT ename FROM scott.emp WHERE empno = " + empId;
            // 4. 执行查询
            rs = stmt.executeQuery(sql);
            // 5. 处理结果
            if (rs.next()) {
                empName = rs.getString("ename");
            }
        } catch (ClassNotFoundException | SQLException e) {
            // 在实际应用中,应该记录更详细的错误信息
            // 这里简单返回错误信息
            empName = "Error: " + e.getMessage();
        } finally {
            // 6. 关闭资源
            try { if (rs != null) rs.close(); } catch (SQLException e) {}
            try { if (stmt != null) stmt.close(); } catch (SQLException e) {}
            try { if (conn != null) conn.close(); } catch (SQLException e) {}
        }
        return empName;
    }
}

操作步骤:

  1. 创建 Java 源代码

    CREATE AND REPLACE JAVA SOURCE named "DatabaseUtils" AS
    -- 将上面的 Java 代码完整粘贴到这里
    ... (完整的 DatabaseUtils.java 代码) ...
    ;
    /
  2. 编译 Java 源代码

    ALTER JAVA SOURCE "DatabaseUtils" COMPILE;
  3. 创建 PL/SQL 调用器函数

    CREATE OR REPLACE FUNCTION get_employee_name(p_emp_id IN NUMBER)
    RETURN VARCHAR2
    AS LANGUAGE JAVA
    NAME 'DatabaseUtils.getEmpNameFromId(int) return java.lang.String';
    /
  4. 测试(确保你有 scott 模式,或者修改表名和模式)

    -- 假设 scott.emp 表存在
    SELECT get_employee_name(7369) AS employee_name FROM DUAL;
    -- 输出:
    -- EMPLOYEE_NAME
    -- ----------------
    -- SMITH

权限管理

执行这些操作需要特定的权限。

  1. 创建 Java 类:用户需要 CREATE JAVA 权限。

    GRANT CREATE JAVA TO your_user;
  2. 外部网络访问:如果你的 Java 代码需要访问数据库以外的网络资源(如调用 Web 服务),你需要:

    • 数据库级别:以 DBA 身份执行 dbms_java.grant_permission('YOUR_USER', 'java.net.SocketPermission', '<<ALL HOSTS>>', 'connect,resolve');
    • JVM 级别:需要设置 JServeroracle.network.ajp.AJPAdapterListenAddressListenPort,这通常由 DBA 完成。

工具和简化操作

手动执行 CREATE JAVA SOURCEALTER JAVA ... COMPILE 比较繁琐,你可以使用更高效的方法:

  1. 使用 loadjava 命令行工具: 这是一个命令行工具,可以直接将 .java.class.jar 文件加载到数据库中并自动编译。

    # 将 HelloWorld.class 加载到数据库中
    loadjava -user your_user/your_password@your_db HelloWorld.class
  2. 使用 SQL Developer: 在 SQL Developer 中,右键点击 "Java" 文件夹 -> "Create Java" -> "Class",可以直接在图形界面中编写和编译 Java 代码,非常方便。

步骤 操作 命令/语句 描述
1 编写 Java IDE (如 IntelliJ, Eclipse) 编写 public static 方法。
2 加载源码 CREATE AND REPLACE JAVA SOURCE ... AS ... 将 Java 代码存入数据库。
3 编译 ALTER JAVA SOURCE "ClassName" COMPILE; 编译 Java 源码为字节码。
4 创建调用器 CREATE OR REPLACE FUNCTION ... AS LANGUAGE JAVA NAME '...'; 创建 PL/SQL 接口,映射 Java 方法。
5 调用 SELECT your_function(...) FROM DUAL; 像调用普通 PL/SQL 函数一样使用。

通过以上步骤,你就可以在 Oracle 存储过程中灵活地调用 Java 代码,极大地扩展了数据库应用的功能边界。

分享:
扫描分享到社交APP
上一篇
下一篇