枫林在线论坛精华区>>技术交流 |
[341089] 主题: 利用Java存储过程简化数据库操作 |
作者: redhat (RedHat) | ||
标题: 利用Java存储过程简化数据库操作[转载] | ||
来自: 192.168.*.* | ||
发贴时间: 2005年04月27日 09:09:11 | ||
长度: 11634字 | ||
利用Java存储过程沟通SQL、XML、Java、J2EE和Web服务。 存储过程(stored procedure)允许将运行于数据库层中的持久性逻辑与 运行于中间层 中的商务逻辑有效地分离开来。这种分离可以降低整个应用程序的复杂性 ,并提供其重 用性、安全性、性能和可伸缩性。 但是,妨碍存储过程广泛采用的一个主要障碍是不同数据库厂商使用各种 专有的、且依 赖于数据库的实现语言。使用基于Java的存储过程可以解决这一问 题。O racle已经实现 了ANSI标准,这些标准规定了从SQL中将静态Java方法作为过程或函数进行 调用的能力。 这种实现被简单地称作"Java存 储过程"。 在本文中,你将了解基于Java的存储过程如何帮助简化商务逻辑、提高其 性能,并扩展 数据库的功能。本文将介绍Oracle如何在数据库内启用基于Java的存储过 程。还会介绍J ava存储过程如何访问数据,以及如何创建基本Java存储过程。 选择PL/SQL还是Java 在考虑Oracle存储过程时,你可能会想到PL/SQL。不过,从Oracle8i开始 ,Oracle已经 在数据库中支持Java,从而为存储过 程提供了不同于PL/SQL的开放式和可 移植的方法。 我可以听到"$64 000问题":"我如何在PL/SQL和Java之间 做出选择?我是否应当忘记已 经学习的所有PL/SQL相关知识,而变为一个Java天地的新手?" 两种语言都适用于数据库编程,都有自己的优点和弱点。在决定选择哪一 种语言时,可 以参考下面根据经验得出的通用规则: 对于要求与SQL进行无缝集成的数据库中心来说则逻辑使用PL/SQL,从而完 成对数据库对 象、类型和特性的访问。 出于与数据库的无关性考虑时,可以选择Java作为开放式的语言来取代PL /SQL,同时也 为了集成和沟通SQL、XML、J2EE和Web服务等各个领域。 OralceJVM使得Java可以运行在数据库中 从Oracle8i版本1(Oralce8.1.5)开始,Oracle便提供紧密集成的Java虚 拟机(JVM), JVM支持Oralce的数据 库会话期结构。任何数据库对话期都可以在第一Ja va代码调用时 启动一个虚拟上专用的JVM,后续的用户可以使用这一已经存在的支持Jav a的会话期。事 实上,所有会话共享同一JVM代码并保持"仅静态"的私有状态 ,而垃圾则收集在单个对 话期空间内,从而为各个Java对话期提供了和SQL操作相同的对话 期隔离 和数据完整性 能力。这里,不需要为了数据完整性而进行单独的Java支持的过程。这一 基于对话期的 结构提供了较小的内存占用率,并使 OracleJVM具有与Oracle数据库一样 的线性SMP可伸 缩性。 创建Java存储过程 要将Java方法转换为Java存储过程需要几个步骤,包括:用loadjava实用 程序将Java类 加载到数据库中,利用调用规范(Call Spec)发布Java方法,将Java方法 、参数类型和 返回类型映射到其SQL的对应部分。下面部分说明如何完成这些步骤。 我将使用一个简单的Hello类,它有一个方法Hello.world(),返回字符串 "Hello world" : public class Hello { public static String world () { return &quo t;Hello world"; } } Loadjava 实用程序 Loadjava是加载Java源文件、Java类文件和Java资源文件的实用程序,它 可以用来验证 字节码,并将Java类和JAR文件布置到数 据库中。它既可以通过命令行调 用,也可以通 过包含于DBMS_JAVA类中的loadjava()方法调用。为了加载我们的Hello.c lass示例, 输 入: loadjava -user scott/tiger Hello.class 从Oracle9i版本2开始,loadjava允许通过为包含在被处理的类中的方法创 建相应的Call Specs来自动将Java类发布为存储过程。Oracle为开发、测试、调试和布 置Java存储过 程提供了Oracle9i JDeveloper。 The Resolver Spec 基于JDK的JVM在列于CLASSPATH中的目录中查找类引用,并对其进行解析。 因为Oracle数 据库类存在于数据库模式中,所以 OracleJVM利用数据库解析器(resolv er)通过列于R esolver Spec中的模式查找并解析类引用。与CLASSPATH不同(CLASSPATH 可以应用于所 有的类),Resover Spec根据每类的情况进行应用。缺省解析器首先在加 载类的模式中 搜寻类,然后在公共同义词(public synonyms)中搜索。 ?loadjava -resolve <myclass> 你可能需要指定不同的解析器,也可以在使用loadjava时强制进行解析, 从而在布置时 确定可能在以后运行时发生的任何问题。 loadjava -resolve -resolver "((* SCOTT) (foo/bar/* OTHERS) (* PUBLIC))" Call Spec和存储过程调用 为了从SQL中调用Java方法(以及从PL/SQl和JDBC中调用),必须首先通过 Call Spec发 布公共静态方法,它为SQL定义方法采用的参数以及返回的SQL类型。 在我们的例子中,我们将利用SQL*Plus连接到数据库,并为Hello.world ()定义一个顶 级Call Spec: SQL> connect scott/tiger SQL> create or replace function h elloworld return VARCHAR2 as language java name 'Hello.world () return java.lang. String'; / Function created. 可以像下面这样调用Java存储过程: SQL> variable myString varchar2[20]; SQL> call helloworld( ) into :myString; Call completed. SQL> print myString; MYSTRING --------------- ------ Hello world Java存储过程可以通过其Call Spec从以下各项中进行调用:SQL DML语句 (INSERT, UPDATE、DELETE、SELECT、CALL、EXPLAIN PLAN、LOCK TABLE和MERGE)、 PL/SQL块、子 程序、程序包以及数据库触发器。Call Spec的美妙之处在于存储过程实现 可以从PL/SQL 转换为Java,反之亦可,这一点对于请求者是透明的。 Call Spec从实现语言中(PL/SQL或Java)中抽象出调用界面,因而使之能 够在原有应用 程序和新的基于Java/J2EE的应用程序之间共享商务逻 辑。但是,在从J ava客户程序调 用在数据库驻留的Java类时,你可能不希望通过PL/SQL包装器(wrapper)。 在以后的版本 中,Oracle 计划提供一种机制,它可以使开发人员略过Call Spec。 高级数据访问控制 Java存储过程可用于控制和限制对Oracle数据的访问,其方法是只允许用 户通过存储过 程管理数据,而存储过程在其调用者的权限内执行,而不能 对表本身进行 访问。例如, 你可以在特定时间内禁止更新数据,或者使管理者只具有查询工资数据的 权利,而不能 进行更新,或者记录所有的访问并通知某一安全机 构。 原有应用程序与J2EE应用程序之间的数据逻辑共享 因为原有应用程序与J2EE应用程序都通过Call Spec调用存储过程,所以J 2EE和非J2EE应 用程序可以共享相同的数据逻辑。由于有了Call Spec,所以不用考虑所用 的是何种实现 语言(无论是PL/SQL还是Java),该数据逻辑都可以共享。 为BMP实体Bean自动生成主关键字 在对EJB实体bean应用BMP时,一个bean实例可以由自动生成的与新插入的 数据相关联的 主关键字惟一确定,它是ejbCreate()的返 回值。可以利用一个插入相应 数据的存储过 程在一个数据库操作中检索ejbCeater()中的该值,并检索或计算主关键字 。作为另一种 方法,也可以利用 JDBC3.0的RETURN_GENERATED_KEYS特性,以一个SQL语 句插入该数据 并检索相应的关键字(或ROWID)。但是,存储过程方法 在各个JDBC驱动 器版本和数据 库之间更具可移植性。 可以用以下三个步骤实现这一模式: > 创建一个Java存储过程,在公共GenPk类中定义一个公共静态Java方法ins ertAccount() 。此方法将插入数据、计算惟一的关键字(通过发出一个序列号),并返 回计算出的关 键字作为主关键字。 定义Call Spec CREATE OR REPLACE PROCEDURE insertAccount(owner IN varchar, bal IN number, newid OUT number) AS LANGUAGE JAVA NAME 'GenPK.insertAccount( java.lang.String [])'; / 在ejbCreate()内调用存储过程 Public AccountPK ejbCreate(String ownerName, int balance) throws CreateException { try { CallableStatement call = conn.prepareCal l{ "{call insertAccount(?, ?, ?)}"}; return new AccountPK(accountID); } } 为CMP实体Bean定制主关键字查找器 查找器方法(Finder methods)用于检索已存在的EJB实体bean实例。主关 键字查找器使 你能够检索惟一标识的EJB实例。对于CMP实体bean,EJB容器根据声 明描 述,自动生成 主关键字查找器findByPrimaryKey()方法。但是,在某些情况下,可能需 要更多的控制 ,例如可能需要专门的查找器,如 findByStoredProcKey()。在这些情况 下,你可以结 合使用Java存储过程和对象关系框架(如Oracle9i应用服务器 [Oracle9i AS] TopLink) 来实现定制的主关键字查找器方法。在将EJB查找器定义为REDIRECT或NAM ED查找器后,T opLink将生成一个SQL查询用 于检索bean实例。 数据驱动的EJB调用 在数据驱动体系结构中,商务逻辑调用可以作为数据库操作(如插入、更 新或删除)的 结果来触发。实现该数据逻辑的Java存储过程可以被声明为数据库 触发器 ,用以调用运 行于中间层J2EE应用服务器的EJB。EJB的调用既可以采用J2EE1.3兼容的服 务器通过Inte roperable Inter-ORB Protocol(IIOP)标准远程方法调用(remote met hod invocation,RMI)实现,也可以通过销售商特定的传输协议(如Oracle9 iAS/Oc4J的ORM I,或者通过BEA WebLogic的T3)用RMI来实现。每个应用服务器提供商在 提供基于IIOP 的RMI,以提供互操作性的同时,都有其自己优化的协议。 Oracle9iAS同 时支持基于IIO P的RMI调用和基于ORMI协议的RMI调用。 数据驱动的消息传送 Oracle9i数据库嵌入了Advanced Queuing(AQ,高级排队),它是一种集 成的、稳定、 可靠、安全、可扩展和事务处理式的消息排队框架。Oracle通过标准的Ja va消息传送系 统 (Java Messaging System,JMS)API为Java开发人员提供AQ功能。Ja va存储过程可 以通过JMS接口调用AQ操作,从而能够实现快速、在会话期内、可扩展 的 、数据驱动的 消息传送。 Java存储过程可以利用JMS调用AQ操作。可以用以下4个步骤实现这一模式 : 创建并启动JMS Queue(为此,可以将以下一些操作嵌入SQL脚本内): execute dbms_aqadm.create_queue_table(queue_table => 'queue1' , queue_payload_type => 'SYS.AQ$_JMS_TEXT_MESSAGE', comment =&g t; 'a test queue', multiple_consumers => false, compatible => '8.1.0' ); execute dbms_aqadm.create_queue( queue_name => 'queue1', queue_table => 'queue1' ); execute dbms_aqadm.start_queue(queue_name => 'queue1'); 创建Java存储过程(代码摘录如下): public static void runTest(String msgBody) { try { // get databa se connection ora_drv = new OracleDriver(); db_conn = ora_drv.defaultConnection(); // setup sender (cf online code sam ple) .. // create message s_msg = s_session.createTextMessage(msgBody); // send message sender.send(s_msg); s_session.commit(); // receive messa ge r_msg = (TextMessage) receiver.receive(); r_session.commit(); // output message text String body = r_msg.getText(); System.out.println("mes sage was '"+body+"'"); ..} } 创建Call Spec: create or replace procedure jmsproc (t1 IN VARCHAR) as language java name 'jmsSample.main (java.lang.String[])'; / 调用存储过程: call jmsproc('hello'); 数据库辅助的Web发布(缓冲失效) 各应用程序结构必须面对的一个共同问题是如果可靠地将数据库信息进行 缓存,以提高 整个系统的性能。JCACHE是一种即将公布的标准规范(JSR 107),它可以 解决这一问题 。它说明了一种对Java对象临时在内存中进行缓存的方法,包括对象的创 建、共享访问 、假脱机(spooling)、失效、 各JVM的一致性等。它可被用于缓存JSP内 最经常读取的 数据,如产品目录和价格列表。利用JCACHE,多数查询的反应时间会因为 有缓存的数据 而加快 (内部测试表明反应时间大约快15倍)。 为了跟踪原始数据的所有变化,并刷新已缓存的数据,Java存储过程会作 为一个触发器 被附加在一个表上。这个表的任何变化都会自动调用该存储过程, 后者再 调出一个已定 义的JSP使JCACHE对象失效,该对象将其状态映射到该数据库表。在失效时 ,紧跟其后的 查询将强制缓存器根据数据库的数据进行更 新。 下面的步骤 阅读关于Java存储过程的更多信息 本文摘自白皮书"释放Java存储过程的能量(Unleash the Power of Java Stored Procedures)",可以在以下位置找到该白皮书: otn.oracle.com/tech/java/java_db/pdf/ OW_30820_JAVA_STORED_PROC_paper.PDF Oracle9i数据库第2版中的新PL/SQL特性 otn.oracle.com/tech/pl_sql/pdf/ Paper_30720_Doc.pdf Resolver Spec otn.oracle.com/docs/products/oracle9i/ doc_library/release2/java.920/a96659.pdf OracleJVM and Java 2 Security otn.oracle.com/docs/products/oracle9i/ doc_library/release2/java.920/a96656.pdf 下载代码 练习本文中的代码示例: otn.oracle.com/sample_code/tech/ java/jsp/Oracle9iJSPSamples.html 了解作为Web服务的存储过程 otn.oracle.com/tech/webservices 扩展数据库的功能 在数据库中直接运行Java代码的一个妙处就在于要实现新的功能,只需要 简单地加载代 码或库,并利用Call Spec制作可用于SQL、PL/SQL、Java、J2EE和非Java API的进入点 (公共静态方法)。Oracle9i数据库用户可以很容易地扩展数据库 功能。Oracle自己利用这种能力来获得新的应用程序和工具包,如XML De veloper Kits (XDKs)。 沟通SQL、PL/SQL、Java、J2EE、.NET和XML Oracle XDK是用Java编写的,并将其公共方法可用作Java存储过程,从而 扩展了数据库 的XML可编程能力。SQL、PL/SQL、Java、J2EE和非 Java(.NET)商务逻辑 都能够访问XM L分析器、XSLT处理器、XPath引擎和XML SQL Utility(XSU)。 XML分析器可以通过xmlparser和xmldom包进行访问。XSU是一种Java实用程 序,它可以由 SQL查询结果或JDBC ResultSet生成XML文档,并将XML文档中的数据写入数 据库表或视图 中。利用XSU,XML输出可以输出为文本、Dom树或DTS。通过 dbms_xmlque ry和dbms_xmls ave包,XSU即可用于PL/SQL。 结论 Oracle数据库与Java VM的集成可以创建可移植、功能强大和与数据库无关 的数据逻辑和 持续性逻辑(persistence logic)。运行于中间层的商务逻辑和运行于数 据库层的数据 逻辑之间的分离提高了应用程序的可扩展性、灵活性和可维护性。 |
||
========== * * * * * ==========
|
返回 |