随着Oracle8i的发布,Oracle 在数据库里支持了二种主要的编程语言PL/SQL和Java。今天,Oracle的许多客户既使用PL/SQL建立数据库应用程序,也使用Java建立数据库应用程序。既然存在二种数据库编程语言,那么就有一个很自然的问题:建立Oracle8i应用程序时,PL/SQL和Java 哪一个更好? 我们来快速地回顾一下,PL/SQL给Oracle数据库开发人员提供了强大的功能,包括:高性能、易使用、无缝地与SQL结合,以及强壮性。现在,PL/SQL依旧是一个成熟的开发数据库应用程序的过程性语言,而且是建立SQL密集型和数据密集型应用程序的理想语言。随着Oracle8i的推出,Oracle 在数据库里引入了Java,给这种十分流行的通用语言提供了强壮的、大规模的平台。 利用企业JavaBean和CORBA,可以用Java开发多层、面向组件的应用程序;也可以用Java开发传统的数据库存储过程。Oracle8i 提供了多种特性,可以简化用PL/SQL和Java建立应用程序的过程,而且可以容易地把二种语言编写的应用程序组合起来。 这份白皮书,提供了有关Oracle8i中PL/SQL和Java特性的技术概述,并就如何利用它们建立应用程序提供了实际可行的指导。白皮书分成四个部分:由于许多Oracle 客户都有现存的PL/SQL应用程序,所以,我们开始时,先描述如何现有的PL/SQL程序与Java组合,扩展现有PL/SQL程序;然后,我们描述二种语言里共有的应用程序编程特性,解释如何把PL/SQL和Java共同使用;在第三部分,描述怎样利用PL/SQL和Java 建立应用程序才算最好(例如:什么时候用PL/SQL最合适,什么时候用Java最合适);最后,我们讨论一些真实的例子,实际演示Oracle的客户们目前在Oracle8i里是如何使用PL/SQL和Java的。 用PL/SQL和JAVA建立应用程序 开始,我们首先看一下拥有PL/SQL应用程序的客户的场景:客户们想在服务器里增加新的Java代码,从而扩充原有的PL/SQL应用程序。有三个特别的问题需要考虑:第一,Oracle8i里支持的主要存储过程类型是什么,可以用什么途径调用它们;第二,Java在Oracle8i里如何工作,Java如何同PL/SQL互操作;第三,Oracle8i 服务器如何处理PL/SQL和Java之间的名称解析。在整个白皮书里, “Java”这个单词,既指标准的Java,也指SQLJ (Java里的嵌入SQL),只有在明确地表明讨论不同概念时,才表示不同的意思。 Oracle8i中存储过程的类型 Oracle8i支持的存储过程类型有几种?Oracle8i 支持四种不同类型的存储过程用PL/SQL或Java,都可以实现全部四种类型的存储过程。这四种存储过程类型是: 存储过程顶级存储过程允许客户用任意商业逻辑扩展SQL。客户用名称调用存储过程,可以在SQL、PL/SQL包、以及“顶级”位置上调用存储过程。 存储函数存储函数实质上与存储过程相同,不同之处在于存储函数向调用者返回值。可以用名称调用存储函数,也可以在SQL、PL/SQL包、以及“顶级”位置上调用存储函数。 数据库触发器:触发器是与特定的表和视图关联的商业规则,修改对表或视图时,SQL自动调用触发器。Oracle8i 提供了几种类型的触发器:在SQLDML语句执行之前或之后激发的触发器;在每一行更新之前或之后激发的触发器;事件触发器(例如:登录、退出、DDL语句、数据库启动或关闭等的触发器);替代(instead-of)触发器。所有这些触发器类型,都可以用PL/SQL或Java编写。 对象类型方法 Oracle8 ™ 发行版8.0和Oracle8i提供了用SQL定义复合数据类型的能力。这些对象类型的方法,可以用Java实现,也可用PL/SQL实现。例如,可以用SQL定义一个订单对象类型purchase_order_t,如下所示: 
  CREATE TYPE purchase_order_t AS OBJECT ( 
  pono NUMBER, 
  custref REF customer_info_t, 
  orderdate DATE, 
  shipdate DATE, 
  line_item_list line_item_list_t, 
  shiptoaddr address_t, 
  MEMBER FUNCTION 
  total_value RETURN NUMBER, 
  ) ;
 然后实现这个对象类型的方法: 
  CREATE OR REPLACE TYPE BODY purchase_order_t AS 
  MEMBER FUNCTION total_value RETURN NUMBER IS 
  i INTEGER; 
  stock stock_info_t; 
  line_item line_item_t; 
  total NUMBER := 0; 
  cost NUMBER; 
  BEGIN 
  // 在这里插入具体的PL/SQL代码或者译Java存储过程的调用。 
  END;
 

解决方案 »

  1.   

    在Oracle 8i 里,这四种存储程序类型的每一种,都可以从不同的调用环境调用,这些调用环境是: SQL语句可以在任何SQL语句内部调用函数。顶级CALL语法使用CALL语句,可以在顶级调用过程和函数。CALL是随Oracle8i新引进的语法。PL/SQL块、子程序、包可以在PL/SQL子程序、包或匿名块里调用它们。请注意:Java存储程序自己可以在匿名的BEGIN … END 块内被调用。触发器的隐式调用。最后,PL/SQL或Java存储过程可以在触发器执行的时候,隐式地被调用。 把JAVA与现存的PL/SQL程序结合 要想理解如何才能把Java 应用程序和现有的PL/SQL存储过程结合起来,我们首先要理解开发Java存储过程的三个步骤: 第一步:编写Java 存储过程:第一步是编写要做成存储过程的Java程序。可以用标准的Java编写,也可以用SQLJ编写?因为存储过程通常都是SQL密集型的,所以用SQLJ编写存储过程,是一个效率较高的方法。 
        public class Foo {
        public static String prependHello(String tail) { 
        return "Hello " + tail;}}
     第二步:步署、发布存储过程:用Java开发工具编写完Java程序后,要把它装载进Oracle8i。要用Oracle提供的loadjava命令行工具,以源文件、二进制文件、.class类文件、Java .jar归档文件的形式,把Java程序装载进Oracle8i中的目标数据库大纲。Loadjava是一个Java程序,它用Oracle的JDBC驱动程序连接服务器,自动把一组Java程序装载进服务器。(还可以使用CREATE JAVA这个工具,它是SQL*Plus的SQLDDL命令) 
        >loadjava -user scott/tiger@oudelsrv-1:5521:ORCL Foo.class
     命令执行之后,会把类foo的方法装入scott的大纲(请参阅第后面有关Java、SQL和PL/SQL名称的内容,了解命名空间解析的问题)。下一步是,把方法登记到SQL上。这一步为什么是必不可少的呢?如果只用PL/SQL,就没有必要显式地把PL/SQL过程登记到SQL上?对SQL来说,每个PL/SQL过程自动就是可见的。反之,在使用Java的时候,所有的Java方法对SQL来说都是不可见的?要让一个Java方法能够作为存储过程,在SQL里调用它,就必须显式地把它“发布”到SQL当中。Java 类和方法不会自动地发布到数据字典、SQL和PL/SQL里,原因有二: Java应用程序里的大多数方法,通常是由其它Java程序调用;而且Java到Java的调用,发生在Java虚拟机环境里,没有必要暴露给SQL。 SQL编译器需要有关SQL数据类型到Java数据类型如何映射参数的指导,还需要正确重载调用的信息,以便给出与原始实际参数值对应的SQL数据类型。这需要开发人员的干预,所以只有某些顶级Java方法需要在SQL和PL/SQL里调用。 如何把Java方法发布到SQL和PL/SQL? 要把Java程序发布到SQL,只需把顶级的Java入口点暴露给SQL,让SQL能够调用它就可以了。这是什么意思呢?我们来看看一个Java实现的数据库触发器:Java触发器可能有多个类和方法调用。但是,在DML语句执行时,只会调用这些方法中的一个,作为初始调用。之后,Java到Java的调用,就完全是在Java虚拟机内进行的。所以,把Java发布到SQL时,只需把顶级的Java入口点(SQL初始调用的Java类或方法),登记到SQL里就可以了。 要把Java 方法发布到SQL,需要声明一个“调用规范”。方法是:用CREATE PROCEDURE语句声明一个过程或函数,并给它定义一个SQL名称,给参数定义与SQL兼容的名称,以及参数和返回类型对应的SQL类型。 
        >CREATE FUNCTION PREPENDHELLO (s VARCHAR2) RETURN VARCHAR2 AS 
        LANGUAGE JAVA NAME ´Foo.prependHello(java.lang.String) 
        return java.lang.String´;
     
      

  2.   

    使用这种技术,只有静态的Java方法,才能从SQL进行调用。从SQL调用Java的另一个方法是使用实例方法。它包括:建立Oracle Objects ™ 对象,用Java方法实现对象的方法。这个技术使用CREATE TYPE BODY命令,提供给数据库的信息与CREATE PROCEDURE命令的信息类似: 
        create or replace type body point is 
        member function jdistance (p point) return number is 
        language java name 
        ´Point4.distance (Point4) return double´;
     第三步:从SQL或 PL/SQL调用Java:存储过程发布之后,它就象一个PL/SQL存储过程一样。可以用在调用规范里指定的SQL名称,在各种环境里调用它: 可以在任何SQL语句内部调用: 
        >SELECT prepend_hello(ENAME) FROM EMP;
     使用CALL格式在顶级调用: 
        >CALL prepend_hello(‘BILL') INTO :x;\
     在PL/SQL过程、包或匿名块的内部,使用与调用其它PL/SQL过程一样的语法调用: 
        >DECLARE 
        emp_name VARCHAR; 
        BEGIN… 
        emp_name := prepend_hello(‘BILL'); 
        … 
        END;
     从一个实例的方法内部,可以调用Oracle对象的方法,从而调用底层的Java实现: 
        select pt.p, pt.p.jdistance(point(0, 0)) from point_table pt;
     最后,既然所有发布的Java子程序,对SQL和PL/SQL来说,都仿佛是一个PL/SQL子程序[内部用Java实现的子程序],那么一个Java子程序就能透明地参与到PL/SQL子程序所发起的服务器到服务器的RPC调用当中,也能参与到远程数据库服务器的SQL发出的分布式事务当中。 Java 程序如何访问SQL和PL/SQL? Java 应用程序使用标准的JDBC语法或SQLJ语法访问SQL和PL/SQL。Oracle8i 提供了内嵌的JDBC驱动程序和内嵌的SQLJ 转换器,它们都提供了与Oracle客户端JDBC驱动程序及SQLJ转换器相同的功能,其中包括对所有Oracle专有数据类型的支持(例如ROWID、REFCursors、及Oracle8对象关系类型)。例如,有这样一个用PL/SQL编写的存储函数prepend_hello。要通过JDBC在Java程序里调用这个存储过程,我们使用下面的标准JDBC语法: 
        public class StaticCurJDBC { 
        … 
        public static String get() throwsSQLException, 
        CoreException { 
        DriverManager.registerDriver(new OracleDriver()); 
        Connection con=DriverManager.getConnection("jdbc:oracle:kprb:");
        Statement stmt = con.createStatement(); 
        ResultSet rs = stmt.executeQuery("SELECT prepend_hello(ENAME) FROM EMP); 
        … 
        }
     用SQLJ调用PL/SQL函数的示例如下: 
        public class StaticCurJDBC { 
        … 
        public static String get() throwsSQLException, 
        CoreException { 
        String p_name; 
        #SQL{SELECT prepend_hello(ENAME) INTO :p_name FROM EMP WHERE empno = :id}; 
        … 
        }
     请注意这个SQLJ程序:对于Java 存储过程 (例如:在数据库中运行的存储过程),不需要设置连接信息,因为SQLJ转换器会自动得到这个信息。 JAVA,SQL, 和PL/SQL名称 完全规范SQL名称或PL/SQL名称,标识着同指定大纲有关的大纲对象。例如,名称scott.getname 代表在大纲scott里的PL/SQL存储过程。 因为SQL名称是相对于大纲而言的,所以在不同的大纲里,可以使用相同的函数名称。Java中的名称,由解析器规范机制解析,这个机制给出一个排好序的Java名称列表,Oracle的大纲会在列表中进行查找。与Java和PL/SQL有关的命名空间,在数据库里被分隔开。对于已经有PL/SQL存储过程的客户,或者准备用Java和PL/SQL共同编写存储过程的用户来说,这个考虑非常重要。因为数据库把这些命名空间分隔开来,所以用户可以拥有名称相同的存储过程,一个用Java实现,另一个用PL/SQL实现。因为Java存储过程的调用描述器或“调用规范”具有SQL名称,所以标准SQL重载机制会象处理PL/SQL存储过程一样来处理Java存储过程。 选http://tech.ccidnet.com/art/321/20061230/991807_1.html