前言
最近在维护一些旧项目中,还发现有些代码是通过调用 Java 类来实现,由于之前没有接触过,后来查找了相关资料,原来 Oracle 数据库支持通过嵌入式 JVM 调用 Java 类,可以利用 Java 存储过程扩展数据库功能,通过 Java Stored Procedure 或 PL/SQL 调用外部 Java 类 的方式将 Java 代码集成到数据库中,实现复杂逻辑、调用外部 API 等功能。
使用场景
Oracle 调用 Java 类可使用在以下场景:
- 复杂的业务逻辑处理:如果一些复杂的算法或业务逻辑使用 PL/SQL 实现效率较低,或者难以实现,可以通过 Java 类完成。
- 调用外部服务或接口:如果数据库需要与外部系统交互(如 HTTP 接口调用、消息队列发送等),则这类任务通过 PL/SQL 无法直接实现。
- 文件操作与日志管理:可以批量生成 CSV 文件或处理文件的输入输出。
- 数据加密与解密:对于敏感数据,可以使用 Java 提供的加密库可以实现高效、安全的加解密功能。
- 批量处理与优化计算:如果经常需要对大量数据进行处理,可以利用 Java 类进行批量数据操作。
由于在生产环境中,Oracle 调用 Java 类的使用频率并不高,现只针对数据加密与解密进行演示,了解一下 Oracle 下使用 Java 类的基本步骤。
相关步骤
💡使用前要确保用户有 CREATE JAVA
和 EXECUTE
权限。
-
编写 Java 代码,后续可以直接使用 Java 代码,class 文件或者 jar 包。
-
将写好的 Java 代码导入到 Oracle 数据库中,有两种方法:一种是使用 loadjava 命令;另一种是在编写PL/SQL的时候编写。以下是使用 loadjava 方式导入 jar 文件到数据库中:由于本使用的是 19c 数据库 pdb 模式,sys 登录后需要先切换到对应的 pdb 下:
sys@ORCL 23:09:12> alter session set container=test_db;
sys@ORCL 23:09:29> !loadjava -user muser/123456@test_db -resolve /home/oracle/scripts/pwd.jar
复制
--查询类是否成功加载
select * from user_objects u where u.OBJECT_TYPE LIKE 'JAVA%';
复制
- 检查类已经成功加载后,编写 encrypt_str 加密函数 与 decrypt_str 解密函数来封装 Java 代码,以实现后面对 java 功能的调用,如下所示:
CREATE OR REPLACE FUNCTION encrypt_str(r IN VARCHAR2) RETURN VARCHAR2 AS
LANGUAGE JAVA NAME 'com/myjob/encrypt/EncryptionUtils.encrypt_str(java.lang.String) return String';
CREATE OR REPLACE FUNCTION decrypt_str(r IN VARCHAR2) RETURN VARCHAR2 AS
LANGUAGE JAVA NAME 'com/myjob/encrypt/EncryptionUtils.decrypt_str(java.lang.String) return String';
复制
💡Java方法的包名需要用“/”,类名用“.” 分隔,Java方法的传入类型要和数据库类型相对应例如: NVARCHAR2和String
Oracle 和 Java 之间的数据类型需要映射,常用类型如下,更详细的对应关系说明可以看Oracle 官方的文档:
Oracle 数据类型 | Java 数据类型 | 备注 |
---|---|---|
VARCHAR2, CHAR | java.lang.String |
字符串类型 |
NUMBER | java.math.BigDecimal |
精确数值类型 |
BINARY_FLOAT | float |
浮点类型(单精度) |
BINARY_DOUBLE | double |
浮点类型(双精度) |
DATE | java.sql.Date |
日期类型 |
TIMESTAMP | java.sql.Timestamp |
时间戳类型 |
RAW, BLOB, CLOB | byte[] , InputStream |
二进制数据或大字段类型 |
- 通过传入相关参数,调用编写好的函数
--加密
select encrypt_str(r => '1122') from dual;
--解密
select decrypt_str(r => '11F5A4A997ECE44196AA501D3D2A5832') from dual;
复制
- 删除相关 Java 类,操作中下:
sys@ORCL 01:05:48> !dropjava -user muser/123456@test_db-v com/myjob/encrypt/EncryptionUtils dropping: class com/myjob/encrypt/EncryptionUtils sys@ORCL 01:08:29> !dropjava -user muser/123456@test_db-v com/myjob/encrypt/EncrypCons dropping: class com/myjob/encrypt/EncrypCons sys@ORCL 01:08:51> !dropjava -user muser/123456@test_db -v META-INF/MANIFEST.MF dropping: resource META-INF/MANIFEST.MF sys@ORCL 01:09:33> !dropjava -user muser/123456@test_db -v .classpath dropping: resource .classpath sys@ORCL 01:09:49> !dropjava -user muser/123456@test_db -v .project dropping: resource .project
复制
总结
由于在生产环境中,Oracle 调用 Java 类的使用频率逐渐降低,在某些特殊场景下或者旧的项目中(如文件处理、轻量级数据转换、加密/解密等),仍然会有部分使用。但大多数现代系统更倾向于将复杂的业务逻辑和外部集成放在中间件或应用层完成,而不是直接在数据库中实现。如需使用,需要对场景、性能和维护成本进行详细评估,尽量优化设计。在使用 Oracle 调用 Java 类过程中,比较容易出现以下三个错误 :
-
ORA-29532
调用中发生异常
解决方法:检查 Java 类逻辑或数据类型映射是否正确。 -
ORA-29540
类未找到
解决方法:是重新加载 Java 类。 -
ORA-29541
解析失败
解决方法:确保所有依赖库也加载到数据库中。