一、背景
前不久,领导布置了一个任务,要在Oracle端以存储过程(函数)的方式调用Java class类。经过一两天折腾,搞定了任务,现在做个简单总结。
二、实现方式
整个过程有两个步骤:创建Java class和创建存储过程,其中创建存储过程(函数)必须在Oracle端进行,而创建java class则有两种方式,第一种是直接在Oracle端进行,第二种是Java IDE中生成class后再导入到Oracle。
经测试,两种方式的效果相同。为方便调试,先按第一种方式进行,成功后将class和函数删除,再按第二种方式重新创建。
三、具体过程
3.1 在Oracle端创建Java class
在Sqlplus或Pl-Sql Developer的sql窗口中进行,示例代码如下:
create or replace and compile java source named javatest as
public class JavaTest
{
public static String FuncTest (String data, String key)
{
return "This is " + data + "... || This is " + key + "...";
}
}
执行后,会分别生成一个名为javatest的Java Source对象和Java class对象。
3.2 在Oracle端创建存储过程
同样在Oracle端中进行,示例代码如下:
create or replace function f_javatest_functest(p_data in varchar2, p_key in varchar2) return varchar2 as
language java name 'JavaTest.FuncTest(java.lang.String, java.lang.String) return java.lang.String';
执行后,会生成一个名为f_javatest_functest的函数。
此后,可以在sql语句中调用该函数:
select f_javatest_functest('This is data...', 'This is key...') from dual;
This is data... || This is key...
3.3 删掉Java Source和函数
在Oracle端中删掉上述步骤中创建的Java Source(会自动删掉Java class,反之则不会)和函数。细节略。
3.4 在IDE中创建java class
在Java IDE中创建相同的class,源文件(.java)或类文件(.class)均可。如果是类文件,要注意编译时JDK须与oracle的JVM保持一致,11g对应JDK1.5,10g对应1.4。细节略。
3.5 向Oracle导入java class
这里需要使用oracle提供的loadjava命令行工具,它可以导入源文件、类文件、依赖包及资源文件等等。该工具与sqlplus在同一目录。
如果该类使用了其它依赖包或资源文件,须在导入该类之前先导入它们:
loadjava -u username/password -r -v D:JarPathyourjar.jar
loadjava -u username/password -r D:PropPathyourprop.properties
考虑到JVM版本差异问题,推荐导入源文件(.java):
loadjava -u username/password -r -v D:PathJavaTest.java
如果不存在JVM版本差异,可以直接导入类文件(.class):
loadjava -u username/password -r D:PathJavaTest.class
导入成功后,可在oracle端中查询到新生成了Java class对象,但没有Java Source对象。因此采用这种方式可以隐藏代码实现细节。
有关loadjava的具体用法,参见loadjava --help。
3.6 重新创建存储过程
与3.2相同,从略。
3.7 删掉或更改java class、依赖包、资源文件
如果是删除单个class,是可以在Sqlplus或Pl-Sql Developer中进行的。但这种方式难以应付有多个依赖包、资源文件的情况,此时要使用dropjava工具。具体用法从略。
在更改java class、依赖包、资源文件后,需要重新编译存储过程(函数)。
四、注意事项
- 存储过程(函数)应尽量少依赖外部jar包,尤其是有嵌套依赖情形的jar,目前没搜索到如何自动加载嵌套依赖class、以及如何防止依赖class冲突的方法;
- 某些情况下,可能需要事先以SYSDBA对用户赋予相应权限,例如:
EXEC Dbms_Java.Grant_Permission('USERNAME','SYS:java.lang.RuntimePermission', '*', 'read , write, execute, delete');
注意:USERNAME若非系统事先所建用户,必须全大写。