admin 管理员组文章数量: 887172
2024年1月15日发(作者:社团聘书模板)
Oracle中的Java体系结构
目前,使用Java来扩展存储程序是一种很流行的方法。在使用Java类库处理数据的过程中,PL/SQL是必不可少的一环,这是因为PL/SQL 封装了Java类库的数据访问,即任何Java存储对象访问的数据都必须经过PL/SQL。
由于本章的所有内容只被最新的数据库版本所支持,因此它独立于本书的其他章节,以下是本章要介绍的内容:
● Oracle中的Java体系结构
● Oracle JDBC的连接类型
● 客户端驱动器(Client-side driver),即JDBC瘦驱动(thin driver)
● Oracle调用接口驱动器,即中间层胖驱动(middle-tier thick driver)
● Oracle 服务器端内部驱动器(Oracle Server-Side Internal Driver),即服务器级的胖驱动
● 在Oracle中创建Java类库
● 创建内部服务器的Java函数
● 创建内部服务器的Java过程
● 创建内部服务器的Java对象
● 创建、装载、删除、使用Java类库时的故障诊断
● 映射Oracle类型
本章将向您展示一张Oracle中巨大的Java组织结构图,在解释了Java的体系结构之后,您还会看到开发和扩展Java组件的方法。
使用Java扩展的原因:
我们将使用PL/SQL作为存储Java类库和其他PL/SQL存储程序或匿名块程序之间的接口。我们还会映射Oracle和Java之间的本地数据类型和用户自定义数据类型,以便能定义有效接口和支持JSP (Java Server Page,Java服务器页面)。
1 Oracle中的Java体系结构
Oracle 9i和10g版本的数据库为开发服务器端或内部Java程序组件提供了一个健壮的体系结构。Java组件采用OO (Object-Oriented,面向对象)的结构,这样的结构非常适合Oracle的对象-关系模型(Object-Relational model)。组件的体系结构实际上就是一个库栈,它包含:
● 操作系统的平台依赖性,例如UNIX、 LINUX、 Microsoft Windows;
● 依赖Oracle数据库的文件和库管理;
● 独立于平台的JVM (Java Virtual Machine,Oracle Java虚拟机);
● Java内核类库,兼容不同的平台;
● Oracle支持的Java API (Application Programming Interfaces,应用程序接口),如SQLJ、JDBC和JNDI;
● Oracle的PL/SQL存储对象,为SQL和PL/SQL程序之间提供接口,就像服务器端Java类库一样。
Oracle和Java库就和普通的文件系统一样来存储和管理应用程序,它们屏蔽了不同操作系统的结构差异和系统限制,从而建立起一个独立于平台的存储、检索和恢复文件的统一处理过程。同时,Java虚拟机为创建有大量文档支持的OO程序提供了一个标准环境。另外,Oracle PL/SQL也为其他PL/SQL存储对象以及SQL访问Java库提供了软件包。
下图5-1给出了Oracle JVM(Java虚拟机)的体系结构。
Oracle JVM使用两种格式的命名空间:长名称和短名称。长名称和Java中类的命名模式是一样的,我们可以用它本来的命名空间来调用存储Java程序。然而,本章中Java示例的名称都是短名称,并且程序也没有放进程序包中。当然,您完全可以将您的Java程序放进程序包中。Java存储代码的命名空间包括了程序包的整个层次。如果命名空间的长度超过30个字符,Oracle在数据字典视图中就使用哈希命名空间。使用DBMS_JAVA包和LONGNAME函数可以获得完整的命名空间,而如果要获取短名称可以使用DBMS_JAVA程序包和SHORTNAME函数。
图5-1 Oracle JVM体系结构
JVM具有自动内存管理的功能,这意味着我们不需要手动分配和释放内存空间。同时,就像PL/SQL一样,Java也是强类型的语言。因此,强类型和垃圾回收器相结合,对内存进行管理,为Java提供了一个简单的、富有弹性的环境,就像PL/SQL的运行时引擎一样。
Java和PL/SQL都是解释语言,因此它们要求JIT(Just-In-Time,即时)编译。Oracle 9i中可以对PL/SQL和Java程序进行本地编译,而这实际上是提前编译了。本地编译将PL/SQL和Java程序的字节代码转换成机器可执行的程序代码。
因为本地编译消除了即时编译的延时,所以提高了执行速度。但不幸的是,它却要花些时间将解释过的程序编译为机器代码。权衡之下,如果您并不经常改变代码,本地编译是一个好的选择。
如下所示,有3种方法可将Oracle的Java文件嵌入到数据库实例中:
(1) 处理过程分两步:(a)使用javac编译Java源文件,产生Java字节码程序。(b)使用Oracle loadjava工具将文件放入数据库实例。
(2) 一步处理即可,使用loadjava工具编译文件,并将编译后的Java类文件放入数据库实例。
(3) 一步处理过程,像处理存储Java类一样使用DDL (Data Definition Language,数据定义语言)创建和编译Java源文件。
Oracle 9i R1中的语法分析程序有时会出现问题,并且在Oracle 9i R1中使用DDL命令创建Java程序可能会失败。在9i R2以及以后的版本中这些问题都得到了解决。本章所有的示例都将编译并通过使用loadjava工具载入数据库实例中。
小提示:
如果选择使用上面的第二种方法,那么在我们试图重写文件时,可能会产生ORA-29533错误,这是因为在一些数据库版本中并不支持loadjava工具的替换(replace)选项。要解决这个问题,您只需要使用dropjava工具并附带–user选项删除
本章假设您对Java有一个基本的了解,即能够编译和运行Java程序。本章所有的示例都提供了实例命令行说明。在附录D中有关于这方面的内容的一个基本指南,并且提供了Java环境配置说明。
Java的存储程序体和传统的PL/SQL程序体很像,由单个会话使用定义者权限或调用者权限访问模式调用它们。但Java在Oracle数据库实例的内部和外部的工作方式有一些不同之处,这些不同之处如下所示:
● 首先是执行的控制有明显的不同,Oracle实例外部的Java应用程序包含main()方法,并通过调用它来运行程序,而在实例内部的Java程序则没有包含main()方法。在Oracle实例中存储的Java程序有两种类型的行为,它们是:
● 第1种Java程序的功能相当于具有函数和过程的包,它是一些不可实例化的类。这就要求程序中的所有变量和方法必须是静态的,即将它们作为类的方法。作为具有函数和过程的PL/SQL 包的镜像,这限制了它们的范围。为了更易于访问外部Java程序,这种程序代码的语法有所改变。
● 第2种Java程序的功能相当于对象类型体的实现,它们是一些可以实例化的类,并且程序中的变量和方法可以是静态的,也可以是非静态的。但与外部Java类不同的是,它们的构造函数不能被重载,即它们只有一个默认的构造函数。JDBC2 API中的SQLData接口用于实例化这种类型的程序,并且实例化还包含了在PL/SQL和Java间映射数据类型。
● Java类以Java字节码的形式保存在一个空文本中,并压缩为Oracle数据库实例的外部Java档案文件。Oracle把它们作为源、类以及Java对象资源来管理。模式中包含一个JAVA$OPTIONS表,它可被DBMS_JAVA包、SET_COMPILER_OPTION和RESET_COMPILER_OPTION过程或GET_COMPILER_OPTION函数访问和配置。
● 内部Java类文件并不支持用户接口,这意味着它们不能被直接输出到控制台或本地声音设备。声音文件可以在Oracle内部处理,但它们不能访问本地声音设备。与Oracle 9i相比,Oracle 10g稍微有些改变,因为它使用的是Java SDK 1.4.x,支持Headless(无头)
AWT。
● Oracle内部的Java类的名称有两种格式。一种是支持标准模式数据库对象的短格式,它最长可以有30个字符。当一个类的名称超过长度限制时,Oracle将自动创建一个哈希名称作为类的短名称,并将长名称存放在别处。
● Oracle内部Java类不支持标准Java的e()方法。但Oracle 9i和Oracle10g支持使用多个分解器来定位类。若使用其中一个来定位类,结果却是运行另一个分解器,我们就会得到意料之外的结果。
● 操作资源是受严格限制的,您必须拥有SYSDBA用户权限才能变更它们。可以使用DBMS_JAVA包和GRANT_PERMISSION过程像IO文件来一样打开操作资源。
● Java线程针对Oracle内部的Java类工作方式与外部类有所不同。Oracle JVM使用的是非抢占的线程模式。这意味着所有的线程运行在一个单一的操作系统线程中,Oracle JVM仅是在线程之间切换上下文。切换上下文的意思是,Oracle JVM以循环的方式在每一个时间段产生一个线程,直至所有线程结束。
注意:
正在使用Oracle版本会告诉您应该使用哪个版本的JDK(Java Software Development
Kit,Java软件开发包)。为简单起见,本章所有的示例都是使用Oracle 9i支持的Java SDK 1.3开发的。同时,它们也被Java SDK 1.4所支持。
Oracle Java开发人员向导列出了两个关键的错误代码,但其实还存在很多其他的错误代码。在这我们并不想列出这些错误代码,而是将它们放在在本章后面的“创建、装载、删除、使用Java类库时的故障诊断”一节介绍。
现在我们已经回顾了Oracle Java体系结构的一些关键组件,下一节将介绍几种JDBC驱动程序。
上一页 首页 下一页
2 Oracle JDBC连接类型
为了满足不同的应用需求,Oracle有3种方法实现JDBC (Java Database Connection,Java 数据库连接)。它们是瘦(thin)连接、胖连接和默认连接,分别对应于客户端驱动、服务器端驱动、调用接口驱动(或中间层驱动)。下一节会分析这3种连接方式。
2.1 客户端驱动或JDBC瘦驱动
Oracle瘦连接大概是Java应用程序、JSP、EJB (Enterprise Java Beans,企业级Java Bean)等最常用的一种连接方式了,它为不直接访问Oracle库文件而创建代码提供了许多便利。
因为建立和配置Oracle JDBC瘦驱动器的要求最低,所以外部Java应用程序能够使用多个这样的连接,但首先得保证Java编程环境已经包含了标准的Java库和Oracle JDBC库。这可以通过配置CLASSPATH环境变量来实现。另外要注意的一点就是,环境变量中必须设置有Oracle 这个Java档案文件的路径。书后的附录D对此作了详细介绍。
不幸的是,如果没有配置并启动数据库监听程序,我们就无法使用Oracle
JDBC瘦驱动器。在每一次连接一个数据库实例时,我们都需要都要输入主机名、监听程序使用的端口号、数据库名和用户名以及口令。
使用客户端驱动的原因:
当Java程序连接Oracle数据库时,我们应该知道连接的配置选项。如果我们了解不同的连接方式的工作原理,那么在应用程序连接Oracle实例时,我们可以更好地选择正确的JDBC驱动程序。
对于Oracle程序集来说,Java是非常有用的扩展。但不幸的是,在选择使用一项Java技术去解决问题之前,我们得理解Java选项之间的细微差别,这对解决问题是非常关键的。我们相信,如果理解了Java选项,那么就能够在我们的应用程序中更好地使用Java技术。
小提示:
如果输入的主机名、监听程序端口号或数据库名不正确,那么Oracle客户端或瘦驱动会返回一个无意义的错误消息。实际上,它会报告17002错误。在JDBC API的Oracle实现中会找到这个错误。附录D中演示了一个检查这个错误的清理机制。
外部Java应用程序、JSP、EJB在使用Oracle JDBC 瘦驱动时会受到限制。一个多线程的Java servlet就是这样一个执行Oracle JDBC瘦驱动文件而受到限制的Java应用程序示例。Oracle JDBC瘦连接可以是开放式的连接,也可以是保守式的连接。
开放式的连接是临时性的连接,它使用HTTP协议进行传输,即时限为15秒的管道TCP套接字连接。这种连接方式非常适合与JSP,但要使用大量资源,因为它必须为每一次通信建立连接。
保守连接在连接过程中始终开启状态提醒(state-aware)TCP套接字。Java
servlet通过使用保守连接来创建和维持数据库连接池。另外,通过使用两层(two-tier)或多层次(n-tier)解决方案实现Java servlet,从而避免了使用通过HTTP协议实现的使用大量资源的、短暂的连接方式。
2.2 Oracle调用接口驱动或中间层胖驱动
和Oracle JDBC瘦驱动器相比,Oracle调用接口(OCI)驱动与Oracle C/C++库耦合得更加紧密。如果要使用Oracle调用接口,我们需要保证PATH、CLASSPATH和LD_LIBRARY_PATH环境变量映射到了Oracle库。这些库都需要基于相同的物理平台或通过存储区域网络(SAN)映射,如UNIX中的NFS。
Java servlet使用OCI驱动可以保持持久连接池。但OCI驱动器的性能不如Oracle JDBC瘦驱动。一般来说,如果在servlet中使用Oracle JDBC瘦驱动,
配置连接会容易一些。但如果要保持Java servlet的活跃连接池,瘦驱动的性能会变得很差。
2.3 Oracle 服务器端内部驱动或服务器层胖驱动
Oracle 服务器端内部驱动同样紧密耦合并依赖于Oracle C/C++ 库。但不幸的是,只有这一种方法可以将Java程序作为Oracle数据库中的存储对象来创建。
Oracle 服务器端内部驱动使用连接类中的defaultConnection()方法连接数据库。如果我们希望在外部测试Java程序,那么在测试时会出现一点问题。我们最好在的开发实例中测试Java代码而不是去创建一个工作区。
与OCI驱动器不同,Oracle 服务器端内部驱动比Oracle JDBC瘦驱动器快。如果您阅读本章并研究了实例代码,您会发现,将Java嵌入Oracle数据库需要一些技巧和技术。
下一节将研究如何创建和检查类库和实例化的Java存储对象。
3 在Oracle中创建Java类库
有两种类型的Java类库可供创建,即调用者接口驱动(中间层)Java类库或服务器端Java类库。
在Apache服务器中,调用接口Java库的行为很像服务器端Java库,它们必须复制到Apache服务器的每个位点上,并使用web服务器负载平衡工具管理。这些组件的行为很像调用Oracle服务器的外部程序,关于这方面的内容在一些介绍企业级Java的书中有更详细的讨论。
在Oracle中创建Java类库的原因:
我们应该知道一个Java类是属于数据库内部Java库还是属于外部Java库。部署在数据库内部的库定义都很明确,但使用的范围却很窄。同样的,外部库组件的功能强大,但使用起来却不如本地存储对象方便。您需要了解这两项技术的特点,以便针对实际应用情况选择好的部署方式。
注意:
如果程序中没有直接包括调用接口驱动,即中间层Java类库,那么引用它们需要指出它们在Oracle OCI库中的路径。但在这里要注意的是,除了Oracle应用程序服务器,别的web服务器上都没有部署OCI库。
作为Oracle数据库的子部件,服务器端Java类库保存在Oracle JVM中。服务器端Java类库是本章的核心内容。接下来的两节将向您介绍创建内部服务器Java函数和过程的方法。
注意:
如果您对Java JDBC连接的配置和测试感到陌生,请参考附录D的说明。
Java程序可以很简单,也可以很复杂,本章中的Java程序示例都是简单易懂的,运行这些示例要使用两个关键可执行程序,它们是:
● javac 将Java程序的文本文件编译成Java可执行文件。
● java 运行Java可执行文件。
Java文件的命名习惯是区分大小写的,因此您应该确保文件的名字和网页代码文件名相同。如果您试图编译一个文件名和类名不相同的Java文件,那么会返回一个错误。另外,Java程序文件的扩展名是小写的.java。
现在我们可以创建一个简单的文件来看一看Java程序的工作原理。如果您使用的是Microsoft Windows系统,打开一个命令行窗口。如果您使用的是UNIX系统,打开一个终端窗口,下面是的代码:
-- Available online as part of file.
// Class definition.
public class HelloWorld1
{
// --------------------------------------------/
// Static main to print Hello World.
public static void main(String args[])
{
// Print the message to console.
n("Hello World.");
} // End of static main.
// --------------------------------------------/
} // End of HelloWorld1 class.
使用下面的命令编译Java文本文件:
javac
如果程序编译成功将不会给控制台返回任何消息,这表示程序语法完全正确。但若要验证Java的可执行文件运行是否正确,则首先使用Microsoft Windows的目录(dir)命令或UNIX的列表(ls)命令找到HelloWorld1.*文件所在的工作目录。在控制台上您会看到下面两个文件:
创建了可执行文件后,使用下面的命令测试文件的执行情况:
java HelloWorld1
注意:
运行Java程序时,不必在要运行的程序名后面加.class扩展名,因为这是默认的。如果在文件名后面加上.class会引发下面异常:sDefFoundError:HelloWorld1/class.
小提示:
如果PATH和CLASSPATH环境变量中没有设置当前工作目录,执行程序时同样会引发sDefFoundError: HelloWorld1/class错误。
返回结果如下:
Hello World.
下一节将介绍创建服务器端即内部服务器Java程序体。我们将学习如何通过创建Java类文件,来支持存储函数和过程以及如何封装PL/SQL包中已有的函数和过程这两方面的内容。接下来两节的内容是连续的,第二节的内容建立在第一节的基础之上。
3.1 创建内部服务器Java函数
通过编写使用在服务器端内部或JDBC胖连接上的Java类文件,可以创建内部服务器Java函数。就像本章前面所介绍的那样,JDBC胖连接依赖于OCI库。Java类文件在载入Oracle JVM后就可以直接访问所有的OCI库了。
创建Java内部即服务器端类文件分3步:首先,创建并编译类文件;接下来使用Oracle loadjava工具将编译过的类文件载入服务器;最后,创建一个Java类文件的PL/SQL包装。
下面假设Java的CLASSPATH 和PATH环境变量是正确的。如果您仍然不能编译或测试Java程序,那么可能是您的环境配置不正确。正如前面所提及的那样,查阅附录D,确保您的环境配置得正确。
使用内部服务器Java函数的原因:
我们使用内部服务器Java函数和编写PL/SQL函数的目的是一样的,都是为了处理并返回一个不包含DML(Data Manipulation Language,数据操作语言)命令的结果,不仅如此,内部Java函数还能够镜像PL/SQL函数和调用外部库来使用JAR (Java Archive Repository,Java档案存储)文件。
当我们使用Java编写应用程序并且希望开发团队使用相同的语言编写服务器端代码时,上面这个特性非常有效。同时这个特性还能使开发团队在编写Java代码时,最大程度上减少错误出现的可能性。
下面这个示例创建了具有两个方法的一个Java类库。类库中的两个方法都重载了,即改变了它们的签名或者说是形参列表。它们返回一个可变长度数组或Java字符串。两个重载的方法将会对应于两个重载PL/SQL函数,它们返回值的类型为本地Oracle数据类型VARCHAR2。的代码如下所示:
-- Available online as part of file.
// Oracle class imports.
import .*;
// Class definition.
public class HelloWorld2
{
// --------------------------------------------/
// The Hello method.
public static String hello()
{
// Call overloaded method with a null String.
return "Hello World.";
} // End of hello() method.
// --------------------------------------------/
// The hello method.
public static String hello(String name)
{
// Call overloaded method with a null String.
return "Hello " + name + ".";
} // End of hello() method.
// --------------------------------------------/
// Static main to test instance outside of Oracle.
public static void main(String args[])
{
// Print the return message to console.
n(());
// Print the return message to console.
n(("Larry"));
} // End of static main.
// --------------------------------------------/
} // End of HelloWorld2 class.
脚本执行以下任务:
● 定义了一个具有两个Hello() 方法的类,但方法经过了重载,即它们具有不同的签名或者说是形参列表。这两个方法都是静态的方法,因为PL/SQL封装包只能调用静态的方法。静态方法并不要求有一个类的实例来运行它,它们的功能很像一个C函数或PL/SQL存储包中的函数。
● 定义一个方法main(),在将程序载入Oracle数据库实例前,您可以使用这个方法来测试程序。当类文件载入Oracle实例时会忽略main()方法。main()方法调用静态Hello()和Hello(String name)方法,并将实参输出到控制台。
一般来说,在将程序载入数据库之前,可以先删除诸如main()方法这样的测试组件。不过如果它们留了下来,也不会影响存储Java类库。
使用下面的命令测试Java程序:
java HelloWorld2
控制台上的输出如下所示:
Hello World.
Hello Larry.
如果您不建立PLSQL模式,那么现在请运行create_脚本。当您建立了PLSQL模式后,就像本章前面介绍的那样,使用javac工具编译程序。接下来,使用loadjava工具将程序载入Oracle JVM中,如下所示:
loadjava -r -f -o -user plsql/plsql
注意:
在Microsoft操作系统中,您可能会得到如下错误提示:"The procedure entry point
kpuhhalo could not be located in the dynamic link library . "(过程的入口点kpu
hhalo不能定位到动态连接库 ),这是因为在您的PATH环境变量中没有设置%ORACLE_HOMEbin%路径。
在PLSQL模式下,loadjava工具命令将Java类文件HelloWorld2载入Oracle JVM中。在将Java类文件载入数据库之后,您需要创建一个PL/SQL封装包来使用它。下面的脚本创建了包和包主体,并将其作为Java类库的封装包。
-- Available online as part of file.
-- Create a PL/SQL wrapper package to a Java class file.
CREATE OR REPLACE PACKAGE hello_world2 AS
-- Define a null argument function.
FUNCTION hello
RETURN VARCHAR2;
-- Define a one argument function.
FUNCTION hello
( who VARCHAR2 )
RETURN VARCHAR2;
END hello_world2;
/
-- Create a PL/SQL wrapper package to a Java class file.
CREATE OR REPLACE PACKAGE BODY hello_world2 AS
-- Define a null argument function.
FUNCTION hello
RETURN VARCHAR2 IS
LANGUAGE JAVA
NAME '() return String';
-- Define a null argument function.
FUNCTION hello
( who VARCHAR2 )
RETURN VARCHAR2 IS
LANGUAGE JAVA
NAME '() return String';
END hello_world2;
/
脚本执行以下任务:
● 创建了两个返回值的类型为VARCHAR2的重载函数Hello,其中一个函数没有参数,另一个函数有一个形参;
● 创建了具有两个重载函数Hello的包主体用于实现一个存储Java类文件。PL/SQL NAME关键字提供对存储Java类文件和返回值的一个引用。您必须给出形参所属类型的完全路径,就像引用这样。返回类型可以是短的String,因为Oracle将其理解为外部数据类型。
您可以通过查询user_objects视图验证目前用于测试的所有组件,如下所示:
-- Available online as part of file.
SELECT object_name
, object_type
, status
FROM user_objects
WHERE object_name IN ('HelloWorld2','HELLO_WORLD2');
脚本返回如下结果:
-- This output is generated from the online file.
OBJECT_NAME OBJECT_TYPE STATUS
------------------------------ ------------ -------
HELLO_WORLD2 PACKAGE VALID
HELLO_WORLD2 PACKAGE BODY VALID
HelloWorld2 JAVA CLASS VALID
如果您得到的结果和上面的不一样,那么在继续前进之前,请查一查是否忽略了哪一步。如果得到的结果相同,那么现在就可以在SQL和PL/SQL中测试Java类库了。您可以在SQL中使用一个查询或在PL/SQL中使用DBMS__LINE语句来测试类库。下面是封装包的一个SQL查询,它使用了内部Java类文件:
SELECT hello_('Paul McCartney')
FROM dual;
查询返回下面的结果:
HELLO_('PAULMCCARTNEY')
-----------------------------------
Hello Paul McCartney.
现在您了解了如何创建Oracle数据库存储Java类文件实例——将方法映射为函数。下一节将研究如何创建组件来实现过程的功能。
3.2 创建内部服务器Java过程
创建过程的规则和创建函数的规则很相似。PL/SQL过程有IN或者IN 和 OUT两种模式。然而,当封装一个Java方法时,在PL/SQL中不能使用IN 和 OUT这种模式。如果您试图定义包主体中含有一个具有IN和OUT模式的过程,那么会引发下面的异常:
PLS-00235: the external type is not appropriate for the parameter
现在我们可以创建一个具有IN模式的过程作为一个Java类方法的封装,当您在过程的上下文中使用Java方法时,Java方法将会返回void类型。
使用内部服务器Java过程的原因:
与编写PL/SQL过程的目的一样,我们使用内部服务器Java过程,是为了处理包含DML命令的结果集,结果集可能返回也可能不返回结果。同样的,内部Java过程也能够镜像PL/SQL函数和调用外部库来使用JAR文件。
当我们使用Java编写应用程序,并且希望开发团队使用相同的语言编写服务器端代码时,上面这个特性非常有效。同时,这个特性还能使开发团队在编写Java代码时,最大程度上减少错误出现的可能性。
下面的Java源文件支持一个具有IN模式的PL/SQL过程:
-- Available online as part of file.
// Oracle class imports.
import .*;
import .*;
// Class definition.
public class HelloWorld3
{
// Define the doDML() method.
public static void doDML(String statement
,String name) throws SQLException
{
// Define a connection for Oracle.
Connection conn = new OracleDriver().defaultConnection();
// Define and initialize a prepared statement.
PreparedStatement ps = eStatement(statement);
// Assign the cursor return.
ing(1,name);
e();
} // End of the doDML() method.
// --------------------------------------------/
// Define the doDQL() method.
public static String doDQL(String statement) throws SQLException
{
// Define and initialize a local return variable.
String result = new String();
// Define a connection for Oracle.
Connection conn = new OracleDriver().defaultConnection();
// Define and initialize a prepared statement.
PreparedStatement ps = eStatement(statement);
// Execute a query.
ResultSet rs = eQuery();
// Use a while-loop even though only one row is returned.
while (())
{
// Assign the cursor return.
result = ing(1);
}
// Return the user name.
return result;
} // End of the doDQL() method.
} // End of HelloWorld3 class.
脚本完成以下任务:
● 定义了一个具有两个静态方法的类,其中一个方法返回void,另一个返回一个映射为VARCHAR2类型的String,这两个方法完成以下功能:
● myDML()方法有两个String类型的形参,第一个接收SQL语句,第二个传送要插入的数据。myDML()方法使用第一个形参创建Connection和Pre
paredStatement,然后将第二个参数映射到SQL语句并执行语句,这就是DML语句的模式;
● myDQL()方法有一个带符号的形参,用于接收SQL查询语句作为实参。myDQL()方法使用这个形参创建Connection和PreparedStatement,并将while-loop循环选取的最后一行记录作为一个String返回。
类文件中没有包含main()方法。若要在数据库外部使用main()方法测试程序,需要将连接转换到客户端驱动或OCI驱动方式。如果您希望在数据库实例外部进行测试,请参阅附录D。
大部分情况下,您已经建立了PLSQL模式,但如果没有建立,那么现在请运行create_脚本。当您建立了PLSQL模式后,就像本章前面介绍的那样,使用javac工具编译程序,然后,使用loadjava工具将程序载入Oracle JVM中,如下所示:
loadjava -r -f -o -user plsql/plsql
在PLSQL模式下,loadjava命令将Java类文件HelloWorld3载入Oracle JVM中。在Java类文件载入数据库以后,您应该创建表mytable和PL/SQL封装包来使用它。使用下面的命令创建mytable表:
-- Available online as part of file.
CREATE TABLE mytable (character VARCHAR2(100));
下面的脚本创建了包和包主体,并将其作为Java类库的封装包:
-- Available online as part of file.
-- Create a PL/SQL wrapper package to a Java class file.
CREATE OR REPLACE PACKAGE hello_world3 AS
-- Define a single argument procedure.
PROCEDURE doDML
( dml VARCHAR2
, input VARCHAR2 );
-- Define a single argument function.
FUNCTION doDQL
( dql VARCHAR2 )
RETURN VARCHAR2;
END hello_world3;
/
-- Create a PL/SQL wrapper package to a Java class file.
CREATE OR REPLACE PACKAGE BODY hello_world3 AS
-- Define a single argument procedure.
PROCEDURE doDML
( dml VARCHAR2
, input VARCHAR2 ) IS
LANGUAGE JAVA
NAME '(,)';
-- Define a single argument function.
FUNCTION doDQL
( dql VARCHAR2 )
RETURN VARCHAR2 IS
LANGUAGE JAVA
NAME '() return String';
END hello_world3;
/
脚本执行以下任务:
● 创建了拥有一个过程和一个函数的包,包完成以下任务:
● 包中的doDML过程具有两个VARCHAR2类型形参。
● 包中的doDQL函数具有一个VARCHAR2类型形参,并返回一个VARCHAR2类型的值。
● 通过将存储Java类文件映射给包,将类中的方法映射给过程和函数, 脚本创建了具有上面的过程和函数的包主体。PL/SQL NAME关键字提供对存储Java类文件和返回值的一个引用。我们必须给出形参所属类型的完全路径,就像引用这样。
我们可以通过查询user_objects视图验证目前用于测试的所有组件,如下所示:
-- Available online as part of file.
SELECT object_name
, object_type
, status
FROM user_objects
WHERE object_name IN ('HelloWorld3','HELLO_WORLD3');
脚本返回如下结果:
-- This output is generated from the online file.
OBJECT_NAME OBJECT_TYPE STATUS
------------------------------ ------------ -------
HELLO_WORLD3 PACKAGE VALID
HELLO_WORLD3 PACKAGE BODY VALID
HelloWorld3 JAVA CLASS VALID
如果您得到的结果和上面的不一样,那么在继续前进之前,请查一查您是否忽略了哪一步。如果得到的结果相同,那么现在就可以在SQL和PL/SQL中测试Java类库了。您可以在SQL中使用一个查询或在PL/SQL中使用DBMS__LINE语句来测试类库。下面是封装包的一个SQL查询,它使用了内部Java类文件:
SELECT hello_('SELECT character FROM mytable')
FROM dual;
查询返回结果如下:
HELLO_('SELECTCHARACTERFROMMYTABLE')
-----------------------------------
Bobby McGee
现在您了解了如何创建Oracle数据库存储实例Java类文件—— 将方法映射为PL/SQL过程。下一节将讨论怎样创建包装为PL/SQL对象类型的真实Java对象。
3.3 创建内部服务器Java对象
Java是面向对象的程序语言。在前面的示例中,Java存储对象仅仅作为静态函数来使用。在Oracle 9i Release 2中介绍的Oracle对象特性,让使用Java来实现意义重大的OO计算模型成为可能。从这个版本开始,我们可以创建一个对象类型的实例,并将它们作为对象来使用。通过本节的学习,在您了解了存储Java对象的实现原理之后,您可以查阅第6章PL/SQL对象的工作原理。
使用内部服务器Java对象的原因:
我们使用内部服务器Java对象和使用PL/SQL对象的原因是一样的。使用Java存储对象的好处在于它可以是线程级的对象,同时还可以是可实例化的。一旦您理解了使用SQLData接口的方法,就会觉得使用Java对象更具价值。Java内部服务器对象能够间接地实例化对象。但Java开发人员却会觉得内部服务器Java对象难以使用,因为他们是使用间接的和外部的接口来处理通信的。
本节举例说明了使用SQLData接口的方法,并解释了支持它的一些概念。我们相信Java开发人员会发现这个特性非常有用,但首先必须要知道使用的技巧。本节应该能帮助您开始使用这个特性。
就像前面提到的那样,服务器端存储Java程序从Oracle 9i开始支持完全运行时对象行为。这意味着在PL/SQL对象类型包装之下,我们能够设计、开发
和实现Java应用程序。这些Java类拥有实例方法,即非静态方法。当然,我们也可以使用库中的静态方法
本章前面通过比较所知道的一些差别在这里仍然适用。通过编写Java类文件和SQL对象类型定义,我们可以创建Java对象库。但当对象类型的实现是一个存储Java对象时,对象类型是没有定义的。
外部Java对象和服务器内部Java对象之间的实质差别在于,创建类的实例的方法不同。在Java类文件中,我们不能直接实例化类文件和使用重写的构造函数。实例化存储Java对象的关键在于SQLData接口。接口通过来回的传递参数值实例化Java类,并返回类的实例或一个引用的副本。
小提示:
在使用一个存储Java对象类时是无法直接实例化默认的构造函数的,同样,我们也不能够使用重写过的构造函数。但如果能知道类作用域内的实体变量,SQLData接口将允许我们给一个实例化的类传递值。另外,实体变量不是静态变量,这些限制在SQLData接口实现时就加上了。
通过在Java类文件中提供一个变量定义和3个具体的方法可以实现SQLData接口。这些组件如下所示:
● 一个String类型的变量sql_type;
● 返回值为String类型的getSQLTypeName()方法;
● 具有两个形参并且返回类型为void的方法readSQL(),其中一个形参SQLInput用于一个流(stream),另一个形参是一个字符串,用于数据类型名;
● 拥有一个形参的方法writeSQL(),其形参SQLOutput用于接收流。
下面的示例说明了实现运行时Java类的一些细节。Java类文件HelloWorld4设计了一个可实例化的Java存储对象类型体,类的源代码如下所示:
-- Available online as part of file.
// Oracle class imports.
import .*;
import .*;
import .*;
import .*;
import e.*;
// Class definition.
public class HelloWorld4 implements SQLData
{
// Define and initialize a private class name variable.
private String className = new String("");
// Define a formal parameter signature variable.
private String instanceName;
// Define a private schema qualified name value.
private String qualifiedName;
// Define a class instance variable to support SQLData Interface.
private String sql_type;
// --------------------------------------------/
// Define default constructor.
public HelloWorld4()
{
// Define local String variables.
String user = new String();
// Use a try-catch block because of SQL statement.
try
{
// Call a method of the inner class.
// Set the class instance variable.
qualifiedName = user + "." + className;
} // End of default constructor.
// --------------------------------------------/
// Define a method to return a qualified name.
public String getQualifiedName() throws SQLException
{
// Define and initialize a return variable.
return iedName + "." + instanceName;
} // End of getQualifiedName() method.
// --------------------------------------------/
// Define a method to return the database object name.
public String getSQLTypeName() throws SQLException
{
// Returns the UDT map value or database object name.
return sql_type;
} // End of getSQLTypeName() method.
// --------------------------------------------/
// Define getUserName() method to query the instance.
public String getUserName() throws SQLException
{
// Define and initialize a local return variable.
String userName = new String();
// Define and initialize a query statement.
String getDatabaseSQL = "SELECT user FROM dual";
// Define a connection for Oracle.
Connection conn = new OracleDriver().defaultConnection();
// Define and initialize a prepared statement.
PreparedStatement ps = eStatement(getDatabaseSQL);
// Execute a query.
ResultSet rs = eQuery();
// Use a while-loop even though only one row is returned.
while (())
{
// Assign the cursor return.
userName = ing(1);
}
// Return the user name.
return userName;
} // End of getUserName() method.
// --------------------------------------------/
// Implements readSQL() method from the SQLData interface.
public void readSQL(SQLInput stream, String typeName) throws SQLException
{
// Define sql_type to read input and signal overloading signatures.
sql_type = typeName;
// Pass values into the class.
instanceName = ring();
} // End of readSQL() method.
// --------------------------------------------/
// Implements readSQL() method from the SQLData interface.
public void writeSQL(SQLOutput stream) throws SQLException
{
// You pass a value back by using a stream function.
// tring('variable_name');
} // End of readSQL() method.
} // End of HelloWorld4 class.
Java类文件执行以下任务:
● 定义5个关键的import语句,确保作为存储Java对象类的导入点;
● 定义了4个数据类型为String的类实例变量,其中,className变量是经过定义和初始化的,instanceName 和qualifiedName变量只是定义了,sql_type变量也只是定义了,并且定义这个变量是为了支持SQLData接口的使用。全部4个变量都是私有(private)变量;
● 定义类的无参数构造函数,这是典型的默认构造函数的形式。当您研究到在PL/SQL中实例化这个对象时,就会明白为什么构造函数这么重要了。qualifiedName变量在默认的构造函数内进行初始化,这是惟一给变量赋值的地方。通过这种实现方法可以在程序运行时,显示出默认构造函数被执行了;
● 定义了5个方法,两个用于测试类,另外3个则是用于实现SQLData接口,它们执行以下任务:
● getQualifiedName()方法返回类的实例变量iedName。如果试图在Java存储类中引用一个类级(class-level)变量来支持一个PL/SQL函数和过程的封装包,将会导致失败。loadjava会引发一个异常来阻止将变量放入数据库实例中;
● getSQLTypeName()方法实现了SQLData接口中的一个方法,同时给局部变量赋予用户自定义类型。这使得类能在Oracle JVM的处理范围之内;
● getUserName()方法查询数据库,以返回存储Java类的当前用户;
● readSQL()方法处理Java存储对象类的输入流,这个示例使用一个直接映射来解释在测试中两个实例化类的区别;
● writeSQL()方法处理Java存储对象类的输出流,示例没有使用输出流的直接映射,但是为了理解方便,还是把语句写在方法里面。这样做的原因是所有变量都是私有的。在类中私有变量都被封装起来,并只能通过公开方法来使用它们。
但如果您没有建立PLSQL模式,那么现在请运行create_脚本。当您建立了PLSQL模式后,就像本章前面介绍的那样,使用javac工具编译程序。然而,还有另外一个命令能使您载入并使用Oracle JVM库编译文件。您可以使用loadjava工具直接载入一个Java源、文本、文件,如下所示:
loadjava -r -f -o -user plsql/plsql
如果您选择使用这些选项,loadjava命令的行为会稍有些改变。它会将Java源作为文本来分析和存储,然后在PLSQL模式下使用Oracle JVM编译Java源,并将编译后的文件以Java字节流的形式存储。
小提示:
在用这种方法将Java类文件载入数据库后,使用dropjava工具就不能删除文件,但如果用dropjava工具删除文件,那么同时也删除了文件。
您需要创建一个SQL对象类型来封装Java存储对象类。下面的脚本创建了对象类型作为Java类对象的一个封装包:
-- Available online as part of file.
-- Create a PL/SQL wrapper package to a Java class file.
CREATE OR REPLACE TYPE hello_world4 AS OBJECT
EXTERNAL NAME 'HelloWorld4' LANGUAGE JAVA
USING SQLData
( instanceName VARCHAR2(100) EXTERNAL NAME ''
, CONSTRUCTOR FUNCTION hello_world4
RETURN SELF AS RESULT
, MEMBER FUNCTION getQualifiedName
RETURN VARCHAR2 AS LANGUAGE JAVA
NAME 'lifiedName() return '
, MEMBER FUNCTION getSQLTypeName
RETURN VARCHAR2 AS LANGUAGE JAVA
NAME 'TypeName() return ' )
INSTANTIABLE FINAL;
/
SQL对象类型封装包执行以下任务:
● 定义USING SQLData子句和一个使用外部名的对象类型,外部名是区分大小写的Java类名。USING SQLData子句要求至少要有一个具有外部名的变量,且外部名是Java数据类型;
● 定义了一个无参数的构造函数,一个经过重写的构造函数将不会被使用;
● 定义了两个函数,一个读取实例qualifiedName值,另一个读取SQLTypeName值。
注意:
试图使用没有映射类型参数的SQLData语句会引发一个异常。如果您希望实例化一个类,但不想给它传递任何参数。您可以在封装包中指定一个空的VARCHAR2(1) EXTERNAL NAME ''。接下来,在PL/SQL程序中实例化PL/SQL封装包时,您只需在SQLData接口的readSQL 和writeSQL方法中避免定义流并将NULL传递给封装包就行了。
在定义了PL/SQL对象类型封装包后,我们会看到对象类型和对象实体都在Oracle实例元数据中注册了。运行下面的查询可以看到这一点:
COL object_name FORMAT A30
COL object_type FORMAT A12
COL status FORMAT A7
SELECT object_name
, object_type
, status
FROM user_objects
WHERE object_name = 'HELLO_WORLD4';
如果运行成功,将会得到下面的输出结果:
OBJECT_NAME OBJECT_TYPE STATUS
------------------------------ ------------ -------
HELLO_WORLD4 TYPE VALID
HELLO_WORLD4 TYPE BODY VALID
如果这个时候使用dropjava工具,TYPE BODY将会变为无效。使用dropjava工具重新装载Java源文件,将会保持TYPE BODY处于无效状态。对象得第一次调用,将产生下面的错误:
-- Available online as part of script as qualified above.
DECLARE
*
ERROR at line 1:
ORA-29549: class orld4 has changed, Java session state cleared
ORA-06512: at "_WORLD4", line 0
ORA-06512: at line 10
对象第二次调用会成功,但Oracle实例元数据仍然报告TYPE BODY无效。这时元数据报告是错误的,我们需要运行ALTER命令修复它。例如,我们可以使用下面的命令:
ALTER TYPE hello_world4 COMPILE BODY;
现在,我们可以使用下面的脚本初始化两个对象实例来测试PL/SQL对象类型封装包:
-- Available online as part of file.
DECLARE
-- Define and instantiate an object instance.
my_obj1 hello_world4 := hello_world4('Adam');
my_obj2 hello_world4 := hello_world4('Eve');
BEGIN
-- Test class instance.
dbms__line('Item #1: ['||my_lifiedName||']');
dbms__line('Item #2: ['||my_lifiedName||']');
dbms__line('Item #3: ['||my_TypeName||']');
dbms__line('Item #4: ['||my_TypeName||']');
-- Test metadata repository with DBMS_JAVA.
dbms__line(
'Item #5: ['||user||'.'||dbms_me('HELLO_WORLD4')||']');
END;
/
我们应该会看到如下的输出:
Item #1: []
Item #2: []
Item #3: [_WORLD4]
Item #4: [_WORLD4]
Item #5: [_WORLD4]
SQLData接口允许传递UDT(User Defined Type,用户定义类型),这意味着我们能够使用任何用户定义的结构。如果我们正在调试Java实例的执行,会发现每次调用实例的方法实际上都重新初始化了类的实例。
下一节将讨论Java类库的故障诊断,这些类库负责创建、装载/删除和使用Java服务端存储对象类。
4 创建、装载、删除、使用Java类库时的故障诊断
本节主要介绍Java类库的故障诊断方法,虽然查找其中的一些问题需要靠直觉,但查找问题的开始阶段还是很需要技巧的。
5.4.1 创建、装载和删除Java类库对象
在创建Java类库时可能会碰到许多问题,它们中很多都是由于语法错误而引发的,但还有一个常见的错误是PATH或CLASSPATH中没有所需类库的路径。
我们应该确保环境变量PATH中包含Oracle数据库带有的Java SDK路径,最好重新查找一下所需的Java类库,并把它的路径加到CLASSPATH中。下面是使用本章的示例需要的最简单设置:
WINDOWS
C:> set PATH=%PATH%;C:%ORACLE_HOME%jdkbin
C:> set CLASSPATH=%CLASSPATH%;C:%ORACLE_HOME%
如果需要使用命令行工具JPublisher,我们需要添加下面两个Java档案文件的路径:
%ORACLE_HOME%
%ORACLE_HOME%
使用故障诊断的原因:
如果我们使用Oracle的一系列高级产品,那么由于发现有用的故障诊断线索而节省的时间就可能会浪费在无用的键盘敲击上了。我们发现Oracle服务器端的Java组件有很多错误,这会使我们误入歧途。因此,我们有必要了解这些错误。
如果故障诊断的步骤中有3到10步是需要人工完成的,那么人们就会对使用这项Oracle技术失去信心。因为这样不能相互印证,从而很难查找出错误。我们相信通过本节的介绍,您很快就可以让程序运行起来,从而节省了不少时间。
UNIX
# export PATH=$PATH:/
# export CLASSPATH=$CLASSPATH:/
如果要使用命令行工具JPublisher,我们需要将这些Java档案文件的路径添加到CLASSPATH环境变量中:
$ORACLE_HOME/sqlj/lib/
$ORACLE_HOME/sqlj/lib/
配置Java档案文件访问的另一个潜在的问题是文件中的LD_LIBRARY_PATH,我们需要检查LD_LIBRARY_PATH,确保它像下面这样设置:
LD_LIBRARY_PATH=C:oracleora92lib;C:oracleora92jdbclib
我们可能会碰到这样的错误,它会提示不能直接从数据库实例中删除Java类文件,这个错误是由下面使用dropjava工具的语句引发的:
C:> dropjava -u plsql/plsql
错误消息应该如下面这样显示:
Error while dropping class HelloWorld4
ORA-29537: class or resource cannot be created or dropped directly
产生错误的原因是使用了loadjava装载了源文件。因此,我们应该使用dropjava删除源文件和类。
注意:
命令的动作总是和它预先的描述是一致的,但偶尔也会从Oracle JVM中将源文件和类文件全部删除掉。
提示环境变量CLASSPATH没有包含某个路径的错误会像下面这样显示:
C:>loadjava -r -f -o -user plsql/plsql
errors : class HelloWorld4
ORA-29521: referenced name oracle/jdbc2/SQLData could not be found
ORA-29521: referenced name oracle/jdbc2/SQLInput could not be found
ORA-29521: referenced name oracle/jdbc2/SQLOutput could not be found
The following operations failed
class HelloWorld4: resolution
exiting : Failures occurred during processing
如果提示产生ORA-29549错误,那意味着您缺少某个Java档案文件的引用。就像本章前面提到的那样,如果删除或替换已经调用过的Java类,也会引发ORA-29549错误。
小提示:
如果我们替换了类文件,应该确保从目标模式调用了它们一次,以避免用户去改变Java会话。
现在,我们已经回顾了创建、装载和删除Java存储对象类文件的大部分内容。下面让我们来检查SQL和PL/SQL环境中的一些错误。
5.4.2 使用Java类库对象
如果使用Java存储对象类,我们应当确保在PL/SQL对象类型定义中只定义一个构造函数,即默认构造函数。
小提示:
除非有其他的Java类库—— 一般是包装成过程和函数来调用构造函数,否则不要重载构造函数。
一个重载构造函数的示例是脚本,脚本引用本章前面的文件。脚本为文件定义了两个构造函数。一个不带参数,另一个带有一个形参。由于在目标类文件中没有定义相同的构造函数,因此我们会认为下面的对象类型定义将会失败:
-- Available online as part of file.
-- Create a PL/SQL wrapper package to a Java class file.
CREATE OR REPLACE TYPE hello_world4 AS OBJECT
EXTERNAL NAME 'HelloWorld4' LANGUAGE JAVA
USING SQLData
( instanceName VARCHAR2(100) EXTERNAL NAME ''
, CONSTRUCTOR FUNCTION hello_world4
RETURN SELF AS RESULT
, CONSTRUCTOR FUNCTION hello_world4
( instanceName VARCHAR2 )
RETURN SELF AS RESULT
, MEMBER FUNCTION getQualifiedName
RETURN VARCHAR2 AS LANGUAGE JAVA
NAME 'lifiedName() return '
, MEMBER FUNCTION getSQLTypeName
RETURN VARCHAR2 AS LANGUAGE JAVA
NAME 'TypeName() return ' )
INSTANTIABLE FINAL;
/
但恰恰相反,编译没有失败,实际上这个错误表示了内部Java程序的能力。我们可以运行脚本中的测试程序,会发现对象类型并不支持重载的构造函数:
-- This is found in file.
DECLARE
-- Define and instantiate an object instance.
my_obj1 hello_world4 := hello_world4('Adam');
my_obj2 hello_world4 := hello_world4('Eve');
PROCEDURE write_debug
( number_in NUMBER
, value_in VARCHAR2 ) IS
BEGIN
INSERT INTO java_debug VALUES (number_in,value_in);
END write_debug;
BEGIN
-- Test class instance.
dbms__line('Item #1: ['||my_lifiedName||']');
write_debug(101,'Item #1 Completed');
dbms__line('Item #2: ['||my_lifiedName||']');
write_debug(102,'Item #2 Completed');
dbms__line('Item #3: ['||my_TypeName||']');
write_debug(103,'Item #3 Completed');
dbms__line('Item #4: ['||my_TypeName||']');
write_debug(104,'Item #4 Completed');
-- Test metadata repository with DBMS_JAVA.
dbms__line(
'Item #5: ['||user||'.'||dbms_me('HELLO_WORLD4')||']');
END;
/
控制台的输出如下所示内容:
-- This output is generated from the file.
DECLARE
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at line 4
这个错误提示的意思是说,带有VARCHAR2类型形参的重载构造函数不支持VARCHAR2类型的值,它真正的意思是如果传递SQLData类型的值,那么它就要作为SQLData类型的值来处理。正如前面提及的那样,SQLData接口使用的方法定义了传递值的方法。
如果是第一次实现存储Java对象类,那么您可能会遇到许多的问题,因此创建一个像下面这样的错误管理表java_debug会让您获益良多:
CREATE TABLE java_debug
( debug_number NUMBER
, debug_value VARCHAR2(4000) );
在Java类文件中添加下面的方法允许写java_debug表:
// Define the debugLog() method.
public void debugLog(int debug_number
,String debug_value) throws SQLException
{
String statement = "INSERT INTO java_debug VALUES (?,?)";
// Define a connection for Oracle.
Connection conn = new OracleDriver().defaultConnection();
// Define and initialize a prepared statement.
PreparedStatement ps = eStatement(statement);
// Assign the cursor return.
(1,debug_number);
ing(2,debug_value);
e();
} // End of the debugLog() method.
现在我们已经了解了有关Java存储对象类故障诊断的大部分内容,下一节将总结Oracle类型到Java类型的映射。
5.5 映射Oracle类型
Oracle所有的原有类型和用户自定义类型都映射了Java类型。当使用SQLData时,我们就映射了单个组件和结构。下面给出了Oracle类型映射到Java类型的对应关系:
SQL Data Types Java Class Data Types
CHAR
LONG
VARCHAR2
r
imal
amp
byte
short
int
long
float
double
SQL Data Types Java Class Data Types
DATE
amp
NUMBER
r
imal
byte
short
int
long
float
double
OPAQUE
RAW
LONG RAW byte[]
ROWID
BFILE
BLOB
(JDK 1.1. x)
CLOB
NCLOB (JDK 1.1. x)
OBJECT
Object types (JDK 1.1.x)
a
a
REF
Reference types (JDK 1.1.x)
a
TABLE
VARRAY (JDK 1.1.x)
Nested table and types a
VARRAY types
Any of the preceding Datum
SQL types
Oracle原有类型和UDT可以通过本章介绍的SQLData约定来使用和管理。Oracle JPublish工具允许开发SQLData占位程序来使用自己的UDT。
5.6 小结
现在我们应该已经了解了实现服务器端或内部Java类库的方法,并能对其进行故障诊断了。通过这些技术的支持,我们可以使用Java创建健壮的应用程序,这提供了比使用PL/SQL更为简单的开发方法。
版权声明:本文标题:在Oracle中调用Java 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1705294445h480090.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论