现在的位置: 首页 > 综合 > 正文

Concept-第24章翻译

2014年11月06日 ⁄ 综合 ⁄ 共 27275字 ⁄ 字号 评论关闭

 

24 SQLPL/SQL,以及Java

这篇文章提供了关于SQLPL/SQL以及Java的概述

这篇文章包含了下面的内容:

*SQL的概述

*过程化语言概述

 

SQL的概述

SQL是一个数据库访问,非过程化语言。用户使用SQL语句来描述想要做的操作,并且SQL语言编译器自动地产生一个过程来操纵数据库并且执行想要执行的任务。

IBM研究所开发并定义了SQL,并且ANSI/ISO已经为关系数据库管理系统重新定义了SQL作为标准的语言。SQL-99标准的最小的子集被称为核心。核心的SQL-99 SQL-92 入门级规范的超集。数据库与SQL-99核心规范广泛地相兼容。

OracleSQL包括许多对ANSI/ISO语言的扩展,并且oracle工具以及应用程序提供额外的语句。Oracle工具SQL*PLUS以及oralce的企业管理器可以让用户在oracle数据库上运行任何ANSI/ISO标准的SQL语句,以及这些工具提供额外的语句或者函数。

尽管一些oracle工具以及应用程序能够简化或者隐藏使用的SQL语句,但是所有的数据库操作都使用SQL语句来执行。任何其他的数据访问方法均会围绕oracle内置的安全性并且潜在地保证数据的安全性和完整性。

 

SQL语句

对在oracle数据库中的信息所执行的所有操作都使用SQL语句来运行。一个语句部分地是由SQL保留字组成的,这些保留字在SQL语言中有特殊的含义,并且不能够用于其他的目的。比如:SELECT以及UPDATE是保留字并且不能够作为表名来使用。

一个SQL语句是一个计算机程序或者指令。该语句必须包含一段完整的SQL语法,例如:

Select last_name,department_id, from employees;

只有完整的SQL语句才能够被执行。比如下面的语句碎片会在SQL语句被执行之前会产生包含文本的错误提示:

Select last_name

 

OracleSQL语句被分为下面的类别:

*数据操作语言语句

*数据定义语言语句

*事务控制语句

*会话控制语句

*系统控制语句

*嵌入式SQL语句

 

数据操作语言语句

数据操作语言语句(DML)是对存在的方案对象进行查询或者操作数据。它们让你能够:

*从一个或者多个表或者视图中查找数据(select);获取操作是可滚动的;

*添加新的数据行到存在的表或者视图中(insert)

*更新存在表或者视图中的列的值(update);

*根据条件向表或者视图中插入或者更新行数据(MERGE);

*从表或者视图中删除数据行(DELETE);

*能够看到SQL语句的执行计划(EXPLAIN  PLAN

*锁住表或者视图,临时地限制其他用户的访问(LOCK TABLE);

 

DML语句是最频繁使用的SQL语句。一些DML语句的例子是:

SELECT last_name ,manager_id,commission_pct+salary FROM employees;

INSERT INTO employees VALUES

    (1234, 'DAVIS', 'SALESMAN', 7698, '14-FEB-1988', 1600, 500, 30);

DELETE FROM employees WHERE last_name IN ('WARD','JONES');

 

DML错误日志

DML语句遇到一个错误时,该DML语句能够继续进行,并且同时会将错误代码以及相关的错误信息记录在错误日志表中。对于长期运行的并且处理大量数据的DML语句来说是非常适合使用DML错误日志功能的。

对于DML语句,加入了新的语法,用户可以设置错误日志表名,语句标签,以及放弃执行条件。放弃执行条件用于判断是否应该中断该语句的执行。对于并行的DML操作,放弃执行条件对于每个子进程都使用。对于并行的操作可以准确的设置放弃执行条件的值为0或者无限值。

使用数据转换发生错误时,oracle试图提供一个有含义的值放入到日志表的列中。比如:oracle可能会记录出现错误的数据转换操作符的第一个操作数。如果该值不能够获取到,那么则为该列的值记录为NULL

 

数据定义语言语句

数据定义语言语句(DDL)定义和删除方案对象,以及更新方案对象的结构。DDL语句使你能够:

*创建,修改,以及删除方案对象一起其他数据库结构,包括数据库本身以及数据库用户(CREATE,ALTER,DROP;

*改变方案对象的名字(RENAME);

*不需要删除对象的结构而是删除方案对象中的所有数据(TRUNCATE);

*授予并且撤消权限和角色(GRANTREVOKE);

*打开和关闭审计选项(AUDITNOAUDIT);

*给数据字典添加注释(COMMIT

 

DDL语句将隐式地提交先前的操作并且启动一个新的事务。DDL语句的一些例子是:

CREATE TABLE plants 

    (COMMON_NAME VARCHAR2 (15), LATIN_NAME VARCHAR2 (40));

DROP TABLE plants;

GRANT SELECT ON employees TO scott;

REVOKE DELETE ON employees FROM scott;

 

事务控制语句

事务控制语句管理由DML语句所做的修改以及将DML语句组成一些事务。事务空子后管理能够使你做下面的事情:

*使一个事务的变更永久(COMMIT

*在事务中撤消变更,可以还原到事务的开始点或者还原到事务的保存点(ROLLBACK

*设置事务的回滚的保持点以标识回滚位置(SAVEPOINT

*设置事务的属性(SET TRANSACTION

 

会话控制语句

会话控制语句管理一个指定用户会话的属性。比如:它们可以允许你:

*通过执行指定的操作,比如:启用或者禁用SQL的跟踪功能(ALTER SESSION),来更改当前的会话;

*为当前的会话启用和禁用角色(权限组)(SET ROLE

 

系统控制语句

系统控制改变oracle数据库服务实例的属性。仅有的系统控制语句是ALTER SYSTEM。它能够允许你改变实例的设置(比如:共享服务进程的最小数量),终止会话以及执行其他任务。

 

嵌入式SQL语句

嵌入式S QL语句将DDLDML以及事务控制语句加入到过程化语言编写的程序中。oracle的预编译器处理嵌入式这样的语句。嵌入式语句能够让你:

*定义,分配,以及释放游标(DECLARE CURSOROPENCLOSE

*指定一个oracle数据库并且连接到oracle数据库中(DECLARE DATABASE,CONNECT

*分配变量名(DECLARE STATEMENT

*初始化描述符(DESCRIBE

*设定如何处理错误和警告(WHENEVER

*解析以及运行SQL语句(PREPAREEXECUTEEXECUTE IMMEDIATE

*从数据库中获取数据(FETCH

 

游标

游标是私有SQL区域的名称(或者是句柄)--私有SQL区域是在内存中的一个区域,在这个区域中存储了被解析的语句以及处理语句的其他信息。

尽管大多数oracle用户依赖oracle工具所提供的自动游标处理功能,oracle的程序接口也提供给应用程序的开发者来对游标有更多的控制。在应用程序的开发过程中,一个游标是一个被命名的可供程序可以使用的资源,游标可以用来解析嵌入到应用程序中的SQL语句。

每个用户会话能够打开多个游标,最多可达到OPEN_SURSORS初始参数设置的值的限制。但是,应用程序应该关闭不再需要使用的游标来节省系统内存。如果由于游标数量的限制,一个游标不能够打开,那么数据库管理员可以修改OPEN_SURSORS初始参数值。

一些语句(主要是DDL语句)需要oracle隐式地提交SQL语句,进而导致需要梯归的游标。比如:一个CREATE TABLE语句为了记录新的表以及列的定义,引起需要对各种数据字典表进行更新。在处理递归游标时需要进行梯归调用;一个游标能够运行数个梯归调用。这些递归游标也使用共享SQL区域来存储其信息。

 

可滚动游标

游标的执行是将查询的结果放进被称为结果集的数据行集合中,结果集可以被顺序的获取或者非顺序的获取。使用可滚动游标,获取数据DML操作则不需要按照向前的顺序进行。用户可以通过oracle提供的接口获取之前已经获取过的数据行,获取在结果集里的第N数据行,或者获取在结果集内从当前位置起的第N行的数据行。

共享SQL

当应用程序发送相同的SQL语句给数据库时Oracle会自动地注意。用来处理第一次出现的语句的SQL区域是共享的,也就是说,之后提交的相同 SQL 语句也使用此 SQL 区。因此,对于完全相同的SQL来说,只要只存在一个SQL区域。因为共享的SQL区域是在共享内存区域中,任何oracle进程能够使用一个共享SQL区域。共享的SQL区域能够减少在数据库服务端的内存使用,因此提高了系统的吞吐量。

在评估语句与已创建的SQL区域的语句是否类似或者相同时,oracle会考虑直接被用户与应用程序提交的SQL语句,也会考虑被DDL语句内部隐式提交的递归SQL语句。

 

解析

解析是SQL语句处理的一个环节。当应用程序提交SQL语句时,应用程序就会向oracle发起一个解析调用。在解析调用阶段,oracle会:

*检查语句语法以及语义上的正确性

*决定是否提交语句的进程是否有权限执行该语句

*为该语句分配一个私有的SQL区域

 

Oracle也判断在库存中是否存在一个共享SQL区域,该SQL区域包含了已经经过解析的并且与新提交的SQL语句相同的语句。如果存在的话,用户进程使用该解析过的语句并且立即运行该语句。如果不存在的话,oracle会产生语句的解析语句,并且用户进程为该语句在库存中分配一个共享区域,并且将该语句已经解析过的语句存储在库存中。

 

注意应用程序为该SQL语句做解析调用与oracle解析该语句的不同。一个被应用程序的解析调用将SQL语句与一个私有的SQL区域相关联。在语句与一个私有的SQL区域相关联之后,可以不再需要你的应用程序进行解析调用就可以重复运行该语句。而oracle进行的解析操作为该语句分配一个共享的SQL区域,一旦共享的SQL区域已经为该语句分配好,那么该语句不需要重复解析就可以运行。

解析调用和解析操作对于执行来说都是成本比较高的操作,所以尽可能少的执行这些解析调用或者解析操作。

 

SQL处理过程

这部分介绍了SQL基本的处理过程。包括下面的内容:

*SQL语句的执行

*DML语句的处理

*DDL语句的处理

*事务的控制

 

SQL语句的执行

24-1 图中列出了处理以及运行一个SQL语句的步骤。Oracle运行这些步骤的顺序可能会有所不同。比如:DEFINE步骤可能会在FETCH步骤之前,主要依赖于你的写的代码。

对于许多oracle工具,一些步骤被自动地执行。大多数用户不需要关心这些细节。但是,当编写oracle有关的应用程序时,这些信息会非常有用。

24-1 在处理SQL语句过程中的步骤:


 

DML语句处理

这部分在SQL语句执行期间所发生的为例来说明在每个DML语句处理步骤。

假设你使用Pro*C程序来增加在一个部门中所有员工的薪水。你使用的程序已经连接到 oracle并选择适当的方案对象来更新employee表。你可以在你的程序中使用下面的SQL语句:

EXEC SQL update employees SET salary =1.10*salary

Where department_id =:department_id;

 

department_id是一个程序变量,包含一个部门编码值。当SQL语句正在运行时,department_id的值是被使用的,并由应用程序所提供。

下面是对于每种语句的执行的步骤:

*步骤1:创建游标

*步骤2:解析语句

*步骤5:绑定任何变量

*步骤7:运行语句

*步骤9:关闭游标

 

可选的是,你可以包括下面的步骤:

*步骤6:语句并行化

 

查询(selects)需要一些额外的步骤,如图24-1

*步骤3:描述查询的结果

*步骤4:定义查询输出

*步骤8:获取查询的数据行

 

步骤1:创建游标

一个应用程序可以通过调用接口来创建一个游标。游标的创建独立于任何SQL语句:任何SQL语句都期望创建一个游标。在大多数应用程序中,游标的创建是自动的。但是,在预编译程序中,游标的创建是能够隐式的或者是显式的声明的。

 

步骤2:解析语句

在解析过程中,SQL语句是被从用户进程中传递到oracle中,并且该SQL语句的解析语句被加载到一个SQL共享区域中。在语句处理步骤期间许多错误会被捕捉到。

解析的过程包含下面的内容:

*翻译SQL语句,验证该语句是一个有效的语句

*查询数据字典,检查表以及列的定义

*获取相关对象的解析锁,以便在语句解析过程中对象的定义不会改变。(但是,解析锁只有在与DDL有冲突的情况下才可以允许打破该解析锁)。

*检查被引用的方案对象的访问权限

*确定最优的语句执行计划

*将解析结果存放到一个共享区域中

*将分布式语句的部分或者全部传递到包含相关数据的远程节点上。

 

如果对于类似的SQL语句的共享QSL区域不再在共享池中存在时,Oracle需要解析一个SQL语句。在这种情况下,新的共享SQL区域被分配,并且语句被解析。

无论语句运行多少次,解析的步骤包括处理只需要做一次。Oracle翻译每个SQL语句只翻译一次,在紧接着引用该语句时就只要重复运行那个别解析的语句即可。

尽管在解析SQL语句过程中会验证该SQL语句,但是解析过程只识别出在语句执行之前的错误。因此,一些错误是不能够被解析所捕捉到的。比如:在数据转换方面的错误或者数据错误(比如:在主键上试图输入重复的值),以及死锁都是错误或者是只有在执行期间才会遇到并且报道的情况。

 

查询过程

查询与其他类型SQL语句不同,因为,如果成功的话,查询返回数据作为结果。而其他语句只是简单地返回成功或者失败,查询可以返回一条数据行或者成千条数据行。查询的结果总是以采取表形式,并且获取数据行可以是按照一行一行的获取或者是按照行集来获取。

一些与查询处理有关的问题产生了。查询不仅包括显式的select语句,也包括在其他SQL语句中的隐式的查询。比如:下面语句中的每个都需要查询作为其执行的一部分:

INSERT INTO table SELECT…

UPDATE table SET x=y WHERE …

DELETE FROM table WHERE ….

CREATE table AS SELECT….

 

除此之外,查询还具有以下的特点:

*需要保证读一致性

*能够为中间的处理使用临时段

*SQL语句处理过程中可能需要经过描述,定义,以及获取数据阶段

 

步骤3:描述查询结果

如果查询结果的特性不确定时,描述步骤是必要的;比如:当查询是由用户交互式的输入时,则需要描述步骤来决定查询结果的特性(数据类型,长度,以及名字)。

 

步骤4;定义查询的输出

在查询的定义步骤中,用户指定了用于接受每个获取值的变量的位置,大小以及数据类型。这些变量称为定义变量。Oracle在需要的时候执行数据类型转换。

 

步骤5:绑定任何变量

在此阶段,oracle知道SQL语句的含义但是还是没有足够的信息来运行该语句。Oracle需要在语句中列出的任何变量的值。在这个例子中,oracle需要depatment_id变量的值。获取这些值的过程就被称为绑定变量。

一个程序必须指定变量值的内存位置。应用程序的终端用户可能没有意识到他们其实制定了绑定变量,因为oracle工具能够简单的提示用户输入新的值。

因为你可以指定变量值的内存地址,你不需要在重新执行语句之前重新绑定变量。你能够改变变量的值并且oracle在每次执行时使用内存地址查询这些变量值。

如果oracle需要执行数据类型转换,那么也必须要指定每个变量值的数据类型和长度(除非这些信息已经被隐式的包含或者是默认的)。

 

步骤6:语句的并行化

Oracle能够使查询并行化(SELECTs,INSERTs,UPDATEs,DELETEs),并且一些DDL操作比如索引的创建,创建一个带有子查询的表,以及在分区上的操作。并行化使用多个进程来执行S QL语句以便提高性能。

 

步骤7:运行语句

在这个步骤过程中,oracle包含所有必要的信息和资源,以便语句能够执行。如果语句是一个查询或者是一个Insert语句,则不需要对任何数据行加锁,因为没有数据行被修改。如果语句是一个UPDATE或者DELETE语句,所有该语句受影响的数据行都被加锁,防止数据库的其他用户使用这些数据行,直到该事务提交了commit,rollback,或者savepoint才会释放这些锁。这样确保数据的完整性。

对于一些语句,用户可以定义执行的次数。这个被称为批量执行。如果设定语句执行n次,则定义和绑定步骤会有设置一个大小为n的数组保存相关设定。

 

步骤8:获取查询的数据行

在获取步骤中,数据行将被选择和排序(如果查询要求排序的话),并且每个连续的获取操作将会获取结果集中的一条记录直到最后一条记录被获取完结束。

 

步骤9:关闭游标

处理SQL语句的最后一个步骤就是关闭游标。

 

DDL语句处理

DDL语句的执行不同于DML语句的执行语句查询,因为一个DDL语句的成功执行需要向数据字典中写数据。对于这些语句,解析操作(步骤)实际上包含解析语句,数据字典查询以及数据字典修改语句的执行。

事务管理,会话管理以及系统SQL语句管理是在解析以及运行步骤中运行的。再次提交这些语句时就可以重复地执行。

 

事务的控制

一般情况下,只有通过对oracle数据库访问的程序接口使应用程序设计者将所关心的各种操作类型分类成为一个事务。事务必须被定义以便任务能够以逻辑单元的方式来完成,并且数据能够保持一致。一个事务应该是由逻辑单元任务的所有必要的部分组成,不多不少。

*在所有被引用的表中的数据应该在事务开始以及事务结束之后都处于一致状态;

*事务应该是由SQL语句组成,并且该SQL语句必须能够保持数据的一致性

比如:两个帐号之间的资金转帐(任务的事务或者逻辑单元)应该包含对一个帐号的借款(一个SQL语句)以及对一个帐号的存款(一个SQL语句)。两个操作应该作为一个任务的逻辑单元要么全部失败要么全部成功;没有借款操作存款操作就会失败。其他相关的操作,比如对一个新帐号的存款,则不应该包含在资金转帐的事务中。

 

优化器的概述

所有的SQL语句都使用优化器,优化器是oracle内部决定访问数据的最有效的手段的一个组件。Oracle也提供了一些技术,这些技术能够使优化器能够更好地执行任务。

有许多不同的方式来处理SQLDML操作(SELECTINSERTUPDATEMERGE  或者DELETE)语句;比如,通过改变表或者索引被访问的顺序。Oracle用来运行一个语句的存储过程能够很大程度上影响语句运行的快慢。优化器在许多访问路径中考虑许多因素选择出最优的方法。

注意:优化器在不同oracle版本中在相同条件下可能做出的决定不同。在最新的版本中,oracle可以使用会使用更多的信息来做出更好的执行决策。

 

你可以通过设置优化器的方法和目标来影响优化器的选择。陈旧的或者是没有统计信息的对象将会自动地被分析。你也可以使用PL/SQL中的DBMS_STATS包来为优化器收集统计信息。

有时候应用程序设计者所掌握的应用程序数据的信息比优化器多,那么应用程序设计者可以选择更有效的方式来执行SQL语句。应用程序设计者能够使用SQL语句中的提示语句来指定语句应该如何运行。

 

执行计划

为了运行DML语句,oracle可能需要执行许多步骤。这些步骤中的每一步或者从数据库的物理存储介质上获取数据行,或者将这些语句准备为用户整理这些语句为用户提交这些语句所需要的形式。Oracle用来执行语句的步骤的集合被称为一个执行计划。一个执行计划包括语句访问每张表的访问方式以及这些表的访问顺序(连表顺序)。执行计划的各步骤的执行顺序不是按照编号来执行的。

 

存储执行概要

存储执行概要是执行计划的概要,是由优化器创建执行计划的概要,此概要主要主要是由一组提示组成。当执行概要被被使用时,这些提示将被应用到编译过程中的各个步骤中。执行概要被存储在OUTLN方案对象中。你可以通过编辑这些被存储的执行概要来优化执行计划。

 

编辑被存储的执行概要

当编辑存储执行概要会话开始时,执行概要被复制到用户的方案对象中。所有编辑操作只对复制的执行概要进行执行,直到用户对所编辑内容满意并且选择发布修改好的执行概要。采用这种方式,用户对执行概要的编辑不会影响到其他用户,其他用户继续使用执行概要的已经发布的版本直到对执行概要的修改被保存。

 

程序化语言概述

oracle中,SQLPL/SQLXML以及Java可以无缝地相互操作,这样就允许开发者搭配使用各种语言中相关的特性。SQL以及PL/SQL组成oracle应用程序开发框架的核心。绝大多数企业后台运行SQL语句,Web应用程序也使用SQL语句来访问数据库。(此时的SQL语句是被打包为Java类如:JDBC),企业应用集成应用程序根据SQL查询语句产生XML,并且各种资料库也构建在SQL数据表之上。这是一种简单的,广泛理解的统一的数据模型。在许多应用程序中SQL语句被单独使用,但SQL语句也被JavaJDBC),oracle调用接口(动态的SQL语句)以及XMLXML SQL工具)。

这部分包括下面的内容:

*PL/SQL的概述

*Java的概述

 

PL/SQL的概述

PL/SQLoracle的程序化语言,是对SQL语句的扩展。它是一种存储并运行于服务端的过程化语言,使用简单,能够与SQL语句无缝集成,具有健壮性,可携带性以及安全性。PL/SQL编译器以及解释器被嵌入到oracle Developer,为开发者开发客户端以及服务器端的程序可以使用一致的开发模式。除此之外,PL/SQL存储过程可以由许多oracle的客户端调用,比如:Pro*C或者oracle的调用接口,以及由Oracle ReportsOracle Forms调用。

PL/SQL使你将SQL语句和过程化的结构结合。使用PL/SQL语句,你可以定义并且运行PL/SQL程序单元比如:存储过程,函数,以及包。PL/SQL程序单元一般会被分类为匿名的块以及存储过程。

匿名块是一个出现在应用程序中的PL/SQL块,并且不会被命名或者被存储在数据库中,在许多应用程序中,能够使用SQL语句的位置就可以使用PL/SQL匿名块。

 

存储过程是一个存储在oracle数据库中的PL/SQL块,并且能够从应用程序中通过名字来调用该存储过程。当用户创建一个存储过程时,oracle解析该存储过程并且将解析过的语句存储在数据库中。Oracle也使用户能够创建和存储函数(类似于存储过程)以及包(包是由一组存储过程或者函数构成)。

 

PL/SQL如何运行

PL/SQL的执行方式可以使用解释执行或者是本地执行。

 

解释执行

oracle9i版本之前的版本,PL/SQL源代码总是被编译为字节码,此种代码可以由oracle数据库服务器提供的可携带虚拟机器来运行,也可以使用Oracle Form产品来运行。从oracle 9i之后的版本,你可以选择使用本地执行以及解释执行。

 

本地执行

为了包含大量计算的程序有最好的性能,可以直接将存储在数据库中的PL/SQL程序的源代码编译为数据库所在平台的目标代码。(这个目标代码将被链接到oracle的数据库服务器上)。

 

PL/SQL引擎是用户用来定义,编译以及运行PL/SQL程序单元的工具。这种引擎是许多 oracle产品的特别的组件,包括oracle数据库服务器。

当许多oracle产品有PL/SQL组件时的同时,这部分主要讲述存储在oracle数据库中并且使用oracle数据库的PL/SQL引擎来处理的程序单元。每个oracle数据库工具中的PL/SQL将在相应的文档中介绍。

24-2 说明了包含在oracle数据库中的PL/SQL引擎。

24-2 包含在oracle数据库中的PL/SQL引擎

 

程序单元是被存储在数据库中。当应用程序调用一个存储在数据库中的存储过程时,oracle加载编译过后的程序单元到系统全局区域(SGA)的共享池中。PL/SQL以及SQL语句执行器协同工作来处理在存储过程中的语句。

 

下面的oracle产品包含一个PL/SQL引擎:

*oracle数据库服务器

*oracle Form(版本3以及版本3之后的)

*SQL*Menu(版本5以及版本5之后的)

*oracle Report(版本2或者版本2之后的)

*Oracle Graphics(版本2或者版本2之后的)

 

你可以在另一个PL/SQL块中调用存储过程,此PL/SQL块或者是匿名块或者上一另一个存储过程。比如:你可以调用从oracle Form中调用一个存储过程(版本3或者是版本3以后的)。

你也可以在使用下面工具开发的应用程序中将匿名块传给oracle

*oracle的预编译器(包括用户出口)

*oracle的调用接口(OCIs

*SQL*Plus

*oracle的企业管理器

 

PL/SQL的语言结构

PL/SQL块能够包括下面的PL/SQL语言结构:

*变量以及常量

*游标

*异常

本节简要介绍每种语言结构:

变量以及常量

变量以及常量能够在存储过程,函数或者包中定义。一个变量或者常量能够在SQL或者PL/SQL语句中使用来捕捉或者提供一个需要的值。

一些交互工具,比如:SQL*PLUS,可以使用户能够在当前的会话中定义变量。使用此种变量的方式与在存储过程或者包中定义的变量一样。

 

游标

游标能够在存储过程,函数或者包中显式地被定义,实现以记录为单位来处理oracle数据。游标也能够通过引擎被隐式地定义(来支持其他数据处理操作)。

 

异常

PL/SQL让你能够显式地处理内部错误以及用户定义的错误,这些在PL/SQL代码处理过程中出现的错误就称为异常。内部异常是由于非法操作引起的,比如:除以0,或者是由于oracle返回给PL/SQL代码的错误。用户定义的异常是显式地定义并且在PL/SQL块中显式抛出,来控制对应用程序特定错误的处理(比如:对一个帐户做借操作之后只剩下负数的情况)。

当一个异常抛出时,PL/SQL代码的执行停止,并且诱发异常处理程序。特定的异常处理程序可以针对内部错误或者用户自定义的错误进行编写。

 

PL/SQL中的动态的SQL

PL/SQL能够运行动态的SQL语句,动态SQL的文本直到语句运行时才被完全确认。动态SQL语句被存储在字符串中,该字符串是在程序被运行时输入或者构建的。这个可以使你能够创建通用的存储过程。比如:动态SQL语句可以创建一个对表操作的存储过程,该表的名字直到运行时才会知道。

你可以写存储过程以及匿名的PL/SQL块包含动态SQL语句,并且可以两种方式来写:

*通过在PL/SQL块中嵌入动态SQL语句

*通过使用DBMS_SQL

除此之外,你可以通过动态SQL语句来声明DML或者DDL语句。这样会帮助你解决不能够在PL/SQL中嵌入静态SQL的问题。比如:你可以在存储过程中使用EXECUTE IMMEDIATE语句或者DBMS_SQL包中提供的PARSE存储过程的方法来在存储过程中声

明一个DROP TABLE语句。

 

PL/SQL程序单元

Oracle使你能够使用过程型方案对象来访问以及操作数据库信息,该过程型方案对象被称为PL/SQL程序单元。存储过程,函数以及包都是PL/SQL程序单元的例子。

 

存储过程以及函数

一个存储过程或者函数是组成SQL语句和其他PL/SQL构件组成的方案对象,存储在数据库中,并且作为一个程序单元来解决特定的问题或者执行相关的任务集合。存储过程以及函数允许调用者提供参数,这些参数可专用于输入值,输出值,或者是输入输出值。存储过程和函数让你能够发挥在结构化程序语言的过程功能,以及SQL语句的简单以及灵活性。

存储过程和函数基本上是相似的,除了函数是只返回一个值给调用者,而存储过程不是,可以返回多个值。为了简单方便,在这章的剩下部分存储过程或者函数被统称为存储过程。

你可以通过以下方式来交互式运行存储过程或者函数:

*使用oracle工具,比如:SQL*Plus

*在数据库代码中显式地调用,比如:在oracle Forms或者在预编译应用程序中

*在另一个存储过程或者触发器中显式地调用

 

24-3 说明了一个存储在数据库中的简单的存储过程,并且可以被一些不同的数据库应用程序调用。

24-3 存储过程

 

下面的存储过程例子是向employee表中插入一条员工记录

 

Procedure hire_employees (last_name VARCHAR2, job_id VARCHAR2, manager_id NUMBER, hire_date DATE, salary NUMBER, commission_pct NUMBER, department_id NUMBER)

 

BEGIN

.

.

INSERT INTO employees VALUES (emp_sequence.NEXTVAL, last_name, job_id, manager_id, hire_date, salary, commission_pct, department_id);

.

.

END

在这个例子中所有的数据库应用程序调用hire_employees存储过程。一个授权的用户能够使用oracle的企业管理器或者SQL*PLUS来运行hire_employees存储过程,使用下面的语句:

EXECUTE hire_employees ('TSMITH', 'CLERK', 1037, SYSDATE, 500, NULL, 20);

 

这个语句向employees表中为TSMITH插入一条新的员工记录。

 

存储过程的优势

存储过程在以下方面提供优势:

*利用定义者的权限过程确保数据安全

存储过程能够帮助确保数据安全。具备数据库对象访问权限的用户可以定义存储过程或者函数,其他用户只有通过调用已经被定义者定义的存储过程或者函数来访问数据,这样就能够限制用户数据库操作。

比如:你可以授予用户访问存储过程的权限,该存储过程是用来更新表,但是你 不能授予用户访问数据库表对象的权限。当一个用户调用存储过程时,存储过程以其拥有者的权限来运行存储过程。具有运行存储过程权限用户(但是没有对低层的表进行查询,更新,或者删除的权限)能够调用存储过程,但是这些用户不能够以任何其他方式来操纵表中的数据。

*使用调用者权限过程来继承权限和方案上下文

调用者的权限过程继承权限以及来自存储过程中调用的方案对象。换句话说,一个调用者权限过程没有与一个特定的用户或者方案对象绑定在一起,并且调用者权限过程的每次执行使用当前用户的权限来操作当前用户的对象。调用权限过程对于应用程序开发者来说可以使应用逻辑集中化,甚至即使低层的数据存储在不同的用户方案中。

比如:用户以管理员的身份来对employees表运行一个更新存储过程能够更新薪水,而以业务员的身份的用户运行同样的存储过程被限制只能够更新地址数据。

 

*改进性能

  *通过网络发送信息的数量与向oracle发送单独的SQL语句或者发送整个PL/SQL块的内容相比要少。因为信息只被发送一次,并且在使用时才被调用。

  *在数据库中存储了存储过程的编译后的形式,所以在执行时不需要在进行编译。

  *如果存储过程在SGA中的共享池中出现的话,那么不需要再从磁盘中获取该存储过程就可以立即执行。

 

*内存分配

因为存储过程充分利用了oracle的共享内存容量的优势,存储过程的仅有的一个副本被加载到内存中可以供多个用户使用。在多个用户之间共享相同的代码会显著地减少应用程序对oracle内存的需要。

 

*改进开发生产效率

存储过程增强了开发生产效率。在一组公用的存储过程的基础上开发设计应用程序,你可以避免编写戎余的代码并且增强你的生产效率。

比如:存储过程能够被编写向emloyees表插入,更新或者删除记录。这些存储过程能够被任何应用程序调用,并且不需要重新编写SQL语句就可以完成这些任务。如果数据管理的方式改变的话,只需要修改这些存储过程,而那些使用存储过程的应用程序不需要修改。

 

*完整性

存储过程改进了应用程序的完整性以及一致性。通过开发基于一组存储过程的应用程序,你可以减少提交代码错误的可能性

比如:你可以测试存储过程或者函数来保证这些存储过程以及函数能够返回精确的结果,并且一旦存储过程以及函数被验证过,应用程序就可以重用这些存储过程以及函数,而不再需要测试。如果被存储过程引用的数据结构发生修改,那么存储过程需要重新编译。那些调用这些存储过程的应用程序不再需要任何修改。

 

存储过程开发指南

当设计存储过程时,使用下面的指南:

*定义存储过程来完成一个单独的任务。不要定义可以完成多个子任务的大型存储过程,因为许多大型存储过程的子任务在一些存储过程中的代码中反而造成了不必要的重复

*不要定义存储过程完成oracle的其他特性已经提供的功能。比如:不要定义存储过程来实现简单的数据完整性约束的功能,只需要声明完整性约束就可以实现

 

匿名的PL/SQL块与存储过程比较

一个存储过程被当作一个方案对象来创建以及存储在数据库中。一旦存储过程被创建以及被编译过,存储过程就可以不需要进行重新编译就可以运行。除此之外,依赖信息被存储在数据字典总来保证每个存储过程的有效性。

 

除了存储过程之外,你可以从一个oracle工具或者一个应用程序通过发送一个没有命名的PL/SQL块给oracle数据库服务端来创建一个匿名PL/SQL块。Oracle编译该PL/SQL块并且将已经被编译过的版本放置在SGA中的共享池中。但是oracle不会将匿名块的源代码或者已经编译过的版本存储在数据库中,并且当实例关闭后不会被重用。 Oracle 的共享 SQL 技术`允许匿名的PL/SQL块放置在共享池中为了能够被重用以及共享直到匿名PL/SQL被刷出共享池。

可以将数据库应用程序中的PL/SQL块改写为数据库存储过程存放在数据库中或者在存放在内存中,你可以在运行时避免了不必要的存储过程重新编译,改进了应用程序以及oralce的整体性能。

 

独立存储过程

没有定义在包内文本中的存储过程被称为独立存储过程。定义在包内文本中的存储过程别认为包中的一部分。

 

存储过程的依赖性跟踪

一个存储过程依赖存储过程体中引用的对象。Oracle自动地跟踪以及管理这些依赖性。比如:如果你修改一个存储过程中引用的表的定义时,那么存储过程必须重新别编译来验证该存储过程能够正常工作。通常,oracle自动地对这些依赖性问提进行管理。

 

外部的存储过程

oracle服务端执行的一个PL/SQL存储过程可以调用以C语言编写的外部程序或者外部函数,并且外部存储过程以及外部函数被存储在共享池中。C程序运行在单独的地址空间,与oracle数据库运行的地址空间不一样。

 

表函数

表函数是能够产生行记录的集合作为输出的函数。换句话,也就是表函数返回集合类型的实例(嵌入表以及数组类型)。你可以使用表函数放置在SQL语句中的FROM语句中的常规表的位置。

Oracle允许表函数以管道的形式输出函数结果。这样可以通过ODCITABLE接口的执行或者使用本地PL/SQL指令来实现。

管道方式能够提高许多应用程序的性能,比如:Oracle Warehouse BuilderOWB)及 cartridges groups 等多种应用程序。

在数据仓库建设的ETL(抽取-转换-加载)过程需要从OLTP系统中抽取数据。被抽取的数据在被加载到数据仓库之前需要完成一系列的转换工作(以过程化语言实现,比如:PL/SQL)。

Oracle也允许并行执行表函数以及非表函数。并行执行提供下面的扩展:

*函数能够直接使用子查询操作返回的数据行集合

*输入的数据行集合能够被分区到一个并行函数的多个实例中。这个函数的开发者可以指定在函数的并行实例中输入的数据行集合如何被分区。

因此,表函数类似于视图。但是,视图是使用SQL定义数据转换,表函数是使用过车工内化的PL/SQL。此特性适合实现复杂的数据转换尤其是在ETL中。

 

PL/SQL

包是存储过程和函数,以及这些存储过程以及函数使用的游标和变量构成的集合作为一个程序单元,存储在数据库中。类似于单独的存储过程和函数,被打包的存储过程和函数能够被应用程序或者用户显式地调用。

Oracle为数据库服务端提供了许多PL/SQL包来扩展数据库的功能以及允许PL/SQL访问SQL的特性。比如:在PL/SQL以及SQL中的ULT_HTTP提供了包能够使HTTP发送请求访问Internet上的数据或者调用oracle Web Server Cartridges。在创建应用程序时或者在创建属于你自己的存储过程时你可以使用oracle提供的包。

创建一个包可以分为两部分:包头以及包体。包头声明了所有公共的程序结构并且包体是定义了所有的程序结构(共有的以及私有的)。两部分分开可以有下面的优势:

*你可以在开发周期中有更大的灵活性。你可以在不许要创建实际的包体就可以创建包头并且包头中的存储结构可以被其他存储过程引用。

*你可以分别修改包含在包体中的存储过程体,以及修改在包头中的声明的公共的存储过程头。只要存储过程头没有修改,引用该修改过的存储过程的对象就不需要标识为无效。那时因为这些存储过程不需要标志为需要重新编译的存储过程。

24-4 说明了用于管理员工的数据库的包,其中包含了许多存储过程。

24-4 存储包

 

数据库应用程序需要的时候显式地调用被打包的存储过程。在对employees_management包的权限被授予之后,用户能够显式地运行包含在该包中的任何一个存储过程。比如:oracle的企业管理器或者SQL*PLUS能够声明下面的语句来运行hire_employees存储过程:

EXECUTE employees_management.hire_employees ('TSMITH', 'CLERK', 1037, SYSDATE, 500, NULL, 20); 

 

包的优势

使用包具有下面的优势:

*封装相关的过程以及变量

存储过程允许你为存储过程,变量,数据类型等等数据库中的单独命名的存储单元封装或者分组。这样在开发过程中提供更好的组织结构。存储结构的封装也使权限的管理更加简单。授予用户使用包的权限就会使被授予者具有访问包中的所有程序结构。

 

*声明共有的以及私有的存储过程,变量,常量,以及 游标

定义包时,用户可以指定变量,游标,以及存储过程是共有的以及私有的。共有的意味着用户可以直接访问包。私有的意味着存储结构对用户来说是不可见的。

比如:包中包含10个存储过程。你能够定义包以使只有三个存储过程是共有的,因此用户可以直接使用。其他剩下的存储过程是私有的,并且是包内部的存储过程访问使用。不要将共有的和私有的存储结构与授予PUBLIC相混淆。

 

*性能更加

当包中的存储过程第一次被调用时,整个包被加载到内存中。这个加载过程只需要执行一次,而对于单独的存储过程来说需要对每个存储过程单独加载,所以会加载多次。因此,当调用相关的包中的存储过程情况发生时,不需要磁盘I/O就可以运行已经在内存中的已经被编译过的代码。

一个包体可以在不影响包头的情况下被替换或者被重新编译。结果,引用包结构的方案对象(总是通过包头)不需要重新编译除非包头中的过程结构被替换。通过使用包,不必要的重新编译数量能够减少,这样就会对整体的数据库性能有所提高。

 

PL/SQL集合以及记录

许多编程技术使用集合类型,比如:数组,包,列表,嵌套表,集,树等集合类型。为了在数据库中支持这些技术,PL/SQL提供了TABLE数据类型以及VARRAY数据类型,这样允许你定义索引表,嵌套表以及变长数组。

 

集合

集合是一组数据类型相同的有序元素。每个元素都有唯一的下标,以标识元素在集合中的位置。

集合与第三代编程语言中的数组类似。集合也可以作为参数传递。所以,你能够在数据库表之间或者在应用程序的客户端以及存储子过程之间使用集合俗话局类型来传递多项数据列。

 

记录

你可以使用%ROWTYPE属性来声明一个记录,此记录代表表中的数据或者是游标中获取的数据行。但是,使用用户自定义的记录,你能够声明属于你自己的字段。

记录包含唯一的已经命名过的字段,这些字段能够具有不同的数据类型。假设你有各种有关员工的数据,比如:员工姓名,薪水,以及雇佣期限。这些数据项在数据类型上不同但是在逻辑上是相关的。一个记录为每一项定义一个字段,让你将这些数据作为逻辑单元来对象。

 

PL/SQL Server Pages

PL/SQL Server PagesPSP)是服务端的Web页面(HTML或者XML),其中可以嵌入以特殊标签标记的PL/SQL脚本。为了能够有动态的Web页面效果,开发者通常用C语言或者Perl编写CGI程序,获取数据以及生成动态网页。这样动态网页的开发以及维护成本是比较高的而且是比较耗时的。

采用脚本技术可以完成动态页面快速开发的需求。小的脚本能够嵌入到HTML页面中,并且不需要改变页面原来基本的对象。脚本中包含逻辑用来产生HTML页面动态的部分,并且在用户请求该页面时这些动态部分才会运行。

HTML内容与应用逻辑分离使地脚本页面更加容易开发,调试以及维护。开发模型越简单,那么脚本语言中对编程技术的要求的就低,使得Web页面编写者可以开发动态的Web页面。

HTML页面中有两种嵌入式脚本:客户端脚本和服务端脚本。客户端脚本被作为HTML页面的一部分返回到浏览器并在浏览器端运行。客户端脚本主要用于HTML页面的客户端导向或者数据校验。服务端脚本,当也别嵌入到HTML页面时,是运行在服务端。服务端脚本是获取以及操纵数据,并且产生HTML内容作为页面的一部分返回给浏览器。PSP脚本是服务端的脚本。

 

PL/SQL网关的作用是从客户端接受HTTP请求,调用指定的PL/SQL存储过程,并且将HTTP的输出返回给客户端。PL/SQL Server Pages是被PSP编译器处理的,该编译器将页面编译为一个PL/SQL存储过程。当存储过程被网关运行时,存储过程就会产生具有动态内容的Web页面。Oracle提供了两种处理PSPPL/SQL网关:

*Oracle Application Server 中的PL/SQL cartridge

*WebDB

 

Java的概述

Java是面向对象的编程语言,适合于开发应用型程序。Java包括以下特性:

*一个Java虚拟机,提供了实现平台独立性的功能基础

*自动存储管理激素后,比如:聚集零散的内存为连续的内存空间

*C语言中继承语法并且加强了强类型转换功能

 

这部分主要包括下面的内容:

*Java以及面向对象技术

*类的层次关系

*接口

*多态性

*Java虚拟机的概述

*oracle为何使用Java

*oracleJava应用程序开发策略

 

Java以及面向对象技术

这部分覆盖了在oracleJava应用程序开发的一些基本的技术。

 

所有面向对象的编程语言支持类的概念。与表定义类似,类是具有共同特征的对象的模板。每个类能够包含下面的元素:

*属性类的对象有具有的静态变量或者实例变量

*方法类可以定义方法或者也可以类从其他类中扩展的继承得到的方法,用户可以调用这些方法

当你创建一个类的对象时,即创建类的实例。实例包含对象的字段,即数据和状态。

24-5 显示了一贯employee类,该类有两个属性:last name(lastName)以及员工的标志(ID

24-5 类和实例

当你创建一个实例,实例的属性存储了单个员工相关的私有信息。也就是,包含在员工实例中的信息也只有该员工知道。比如:图4-5 显示了员工的两个实例—Smith以及Jones。每个实例包含与单个员工相关的信息。

 

属性

在实例中的属性被认为是字段。实例字段与关系型表中的字段类似。类定义了字段,以及每个字段的数据类型。你可以在Java中声明字段指定为静态的,公共的,私有的,保护的或者默认的访问方式。

*公共的,私有的,保护的,或者默认的访问字段是在每个实例中创建的

*静态的字段就象全局变量类似,员工类的所有实例均可以访问静态变量存储的信息

Java语言规范还定义了所有字段的数据的可见性的规则。数据的可见性规则定义了在何种情况下用户可以访问这些段的信息。

 

方法

类也定义了用户可以调用类的实例的方法。方法是以Java来编写的,并且定义了对象的行为。封装的实质就是将状态和行为捆绑在一起。这也是所有面向对象编程共有的属性。如果你定义了Employees类,声明那每个员工的ID是私有的字段,其他对象可以通过返回该字段的方法来访问该私有字段。在这个例子中,对象能够通过Employee.getid方法获取员工的ID

除此之外,使用封装,你可以声明Employee.getid方法为私有的,或者你可以决定不编写Employee.getid方法。封装技术能够帮助你编写出那些可重用但不可误用的程序。封装技术使只有声明为共有的对象才能供所有用户使用,其他字段和方法是私有的。私有字段和方法只能够被内部对象处理使用。

 

类的层次关系

Java中定义的类只属于巨大类层次关系中的一环。在类层次关系的最顶层是Object类。当你沿着类的超类继承链向上追溯,发现在Java中的任意层次的所有的类都继承于Object类。当我们说类B继承于类A,类B的每个实例包含在类B中定义的所有字段以及包含类A中定义的所有字段。比如:图24-6FullTimeEmployee类包含定义在Employee类中的id以及lastname字段,因为FullTimeEmployee类继承于Employee类。除此之外,FullTimeEmployee类添加了其他字段,bonus字段,该字段只包含在FullTimeEmployee类中。

你可以对类B的实例中调用定义在类B还是类A上的方法。在员工的例子中,FullTimeEmployee类的实例能够调用定义在该;类中的方法或者是调用定义在Employee类中的方法。

24-6 根据继承关系定位行为和状态

 

B的实例可以替代类A的实例,因此继承是面向对象语言实现代码重用的另一个重要方式。你可以创建新的类时定义该类的行为和状态,同时也可以充分利用类库中的超类中已经存在的功能。

 

接口

Java只支持单独的继承;也就是,每个类有一个并且仅只有一个父类。如果必须要继承多个源,Java提供了接口作为多重继承的解决方法,这种方法避免了多重继承伴随而来的复杂性以及易混淆性。接口类似于类,但是接口只定义了方法,但没有定义具体实现。方法是在实现接口的类中实现的。当一个单独的类同时支持多个接口,那么则称为多重继承。

 

多态性

假设在Employee例子中的,不同类型的员工都需要根据工作时间来计算薪水。薪水的计算对于不同类型的员工有不同的计算方法。

*FullTimeEmployees需要判断是否具有发放奖金的条件

*NonExemptEmployees需要方法加班的薪水

在传统的过程化语言中,开发者需要使用case ..when..语句来处理定义的不同情况。

switch (employee.type) {

case: Employee

return employee.salaryToDate;

case: FullTimeEmployee

return employee.salaryToDate + employee.bonusToDate;

...

如果你添加一个新的员工类,那么你必须更新你的switch语句。如果你修改你的数据结构,那么你必须修改所有switch语句来适应新的数据结构。

在面向对象语言中,比如:Java,用户需要在employee类的基础上为其子类实现compensationToDate方法,来处理每个子类的特殊情况。比如:你可以为NonExemptEmployee类实现按照以下方式实现compensationToDate方法:

private float compensationToDate() {

return super.compensationToDate() + this.overtimeToDate();

}

FullTimeEmployee 类实现的方法如下:

private float compensationToDate() {

return super.compensationToDate() + this.bonusToDate();

}

 

所有不同的类调用同名的compensationToDate方法可以让你调用相同的方法但是接受到不同的结果,不需要知道使用的员工的类型。你不需要写特别的方法来处理FullTimeEmployees以及PartTimeEployees类。这种令不同的对象对相同的消息以不同的方式反映的能力被称为多态性。

除此之外,你能够创建一个全新的类,该类不需要继承Employee—Contractor,并且在新建的类中实现compensationToDate方法。根据日期来计算薪水的程序可以遍历薪水册中的所有员工,不管这些员工是否是全职的,兼职的,还是承包人,并且对于每个员工分别调用compensationToDate方法并对返回的结果求和。你可以修改单独的compensationToDate方法的实现,并且对于方法的调用者来说该方法的运行不会有任何影响。比如:你能够对存在的类添加新的字段。

 

Java虚拟机的概述

与其他高阶计算机语言不同,Java源代码被编译为低级指令。在Java中,这些指令被称为字节码(因为这些指令的存储容量为一个字节)。大多数其他语言比如C语言根据计算机的体系结构不同被编译为不同的指令,比如:对于Intel或者HP处理器特有的指令。Java源代码被编译为一个标准的,独立于平台的字节码的集合,这些字节码运行在Java的虚拟机(JVM)上。JVM是一个特殊的程序,对运行Java代码的特定的平台进行优化。

24-7 说明了Java是如何维护平台的独立性。Java源代码被编译为字节码,字节码是独立于平台的。每个平台必须安装与特定的操作系统对应的JVM。通过JVMJava源代码编译为字节码解释为相关的平台上的操作。

24-7 Java组件结构

 

当你开发一个Java程序时,你使用以Java语言编写的预先定义的核心类库。Java的核心类库在逻辑上分为多个包(包提供经常使用的功能,比如:基本的语言支持:Java.langI/Ojava.io,以及网络访问:java.net)。JVM以及核心类库协同工作提供了一个平台,在这个平态上Java程序员能够自信地开发程序,该程序能够在任何支持Java的硬件和操作系统中执行。这个概念就是Java的“一次编写,随处运行“的理念。

24-8 说明了oracleJava应用程序是如何构建于Java的核心类库上,以及Java的核心类库又是如何运行在JVM上。因为OracleJava支持系统被放置在数据库中,JVMoracle数据库交互,而不是直接与操作系统交互。

24-8 Java组件结构

 

Sun 微系统公司已经公开发布了Java语言以及JVM的规范。Java语言规范定义了Java的语法以及语义;JVM 规范则为运行字节码的计算机定义了必要的低级行为。Sun 微系统公司还提供了兼容性测试套件,供JVM开发者测试其产品是否符合规范要求。测试套件被称为Java 兼容性工具包(JCK)。OracleJVM的实现是完全遵循JCK规范。整体的Java策略中的部分就是提供一个公开的规范标准,并且提供验证是否符合规范的简单方式,允许第三方厂商都能够为Java的跨平台提供统一的支持。

 

为何在oracle中使用Java

你可以在数据库中编写和加载Java应用程序,因为Java是安全的语言。Java不会干预Java代码运行所在的操作系统。一些语言,比如C语言,能够在数据库中导致安全问题;java,因为其设计思想,是一种安全性语言,允许在数据库中存在。

尽管Java向开发者呈现了许多优势,但是提供一个可伸缩的方式来支持Java服务端的应用程序的JVM的实现是个挑战。这部分就讨论这些挑战的问题:

*多线程 

*自动存储管理

*空间使用

*性能

*动态类加载

 

多线程

多线程支持被认为是Java中关键的可伸缩特性。JAVA语言与其他语言相比,JAVA语言和类库使开发共享服务应用程序更加容易,但是以任何语言编写可靠的,可伸缩的共享服务应用程序代码来说还是比较艰巨的任务。

作为数据库服务器,oracle能够为成千个用户高效的调度操作。OracleJVM使用RDBMS服务器工具来并发地为成千个用户调度Java执行操作。尽管oracle支持Java语言规范中的并且满足JSL以及JCK需要的多线程特性,在数据库的范围内使用多线程不会增加可伸缩性。使用数据库的嵌入式的可伸缩性可以减少编写共享服务Java服务端应用程序。通过编写单线程服务的Java应用程序,用户应该使用数据库的工具来为用户调度单线程服务的Java应用程序的并行执行。数据库在每个应用程序之间负责调度,因此,用户不需要管理多线程就可以实现可伸缩性。用户还是能够编写共享服务Java应用程序,但是多Java线程不会提高服务的性能。

Java中实现多线程的一个困难是多线程的相互交互以及自动存储管理,或者垃圾回收。在JVM中执行的垃圾器不知道哪些Java语言线程正在执行或者低层的操作系统是如何调度这些线程的。

*oracle模型一个单独的用户与一个单独的Java语言线程对应;同样单独的资源回收器管理所有来自用户的资源。资源回收器根据对象的生命周期以及大小采用不同的技术来处理对象的分配以及回收。在负载比较严整的共享服务中,应用程序的性能好坏取决于操作系统对原生线程的支持,操作系统对原生线程的支持可能存在不可靠以及对伸缩性有限制的问题。这样的实现方式的高可伸缩性是不能被保证的。

*oracleJVM模型即使当成千个用户连接到服务器,并且运行相同的Java代码,在效果上与每个用户在他自己的Java虚拟机上运行属于他自己的Java代码一样。OracleJVM使用oracleRDBMS的可伸缩性方法主要负责充分利用好操作系统的进程和线程。这种方法的结果是,JVM的资源回收器变得更加可靠并且高效,因为JVM的资源回收器从来不需要从多个用户中在任何时候收集资源,只需对一个用户的资源进行管理。

 

自动存储管理

资源回收是Java的自动存储管理的主要的特性,不需要Java开发员显式地分配和释放内存。因此,这样就不会出现大量的内存泄露,内存泄露的情况是经常发生在C程序或者C++程序中。对于这样的优势也牺牲了一些成本:资源回收也会影响程序执行速度和空间使用。尽管许多文章讨论资源回收是否具有可行性以及其优劣,与其他机制相比较资源回收的成本还是可以接受的。

对于JVM开发者来说寻求提供高可伸缩性以及高性能的Java平台,资源回收带来一些挑战。OracleJVM以下面的方式来解决这些挑,战:

*oracleJVM使用oracle的调度功能,该调度功能能有效的管理用户;

*对于多用户环境下来说资源回收算法没有复杂化,因为资源回收只针对单一会话中的单一用户。OracleJVM有个大的优势就是当用户的数量增加时,内存管理的任务的负载以及复杂性不会增加。内存管理在一个会话中执行对象的分配以及回收---可以理解为单一用户的操作活动

*oracleJVM根据是使用的内存的类型的不同来使用不同的资源回收技术。这些技术提供高效性以及低负荷。

 

空间使用

执行Java程序的空间使用情况受多种因素影响:

*程序本身的大小程序中包含多少类和方法以及有多少代码

*程序的复杂性除了程序本身,当程序运行时,oracleJVM使用的核心类库的数量

*JVM使用的状态的数量—JVM分配多少对象,对象的大小,以及对象之间相互调用保留的信息有多少

*资源回收和内存管理处理执行程序的需求的能力,此因素经常是不确定的。对象的分配速度以及对象被其他对象使用的情况是对此因素是有影响的。

 

从可伸缩的角度是去观察,支持许多用户并发的关键是让每个用户使用的空间使用最小化。OracleJVM通过将提供给用户的只读数据,比如:Java字节码,放置到共享内存中来保持每个用户使用的空间是最小。适当的资源回收算法应用到调用以及会话使用内存中也有助于使每个用户的会话使用最小的空间。OracleJVM使用三种资源回收算法来维护用户会话使用的内存:

*Generational scavenging—针对生命周期较短的对象

*Mark and lazy sweep collection—针对单次调用期间使用的对象

*Copying collector—针对生命周期较长的对象,在整个会话期间使用的对象

 

性能

OracleJVM的性能得到提高是通过执行一个本地的编译器。JavaJVM中运行独立于平台的字节码,而JVM则需要和特定的硬件平台相互交互。在软件中划分的层次越多,系统的性能就会降低。因为Java需要通过中间层来解释独立于平台的字节码,那么对于Java应用程序来说就会有一定程度的性能损失,而在依赖于平台的语言比如C语言就不会存在这些性能的损失因为不需要中间层的解释。为了解决这个问题,一些JVM开发商开发了本地编译器。本地编译器将Java字节码转换为依赖于平台的本地码,这样就消除了解释的步骤并且改进了性能。

下面的表描述了对于本地编译的两种方法:

本地编译方法

描述

即时编译

即时编译器(JIT)在语句运行期间很快地将Java的字节码编译为本地(特定平台)计算机的代码。JIT编译器不会在运行的平台上生成一个可执行文件;而是,在将Java字节码转换为基于平台的代码,在转换操作之后再直接在平台上运行。这种编译器适合用于运行比较频繁的Java代码,经过JIT编译器编译过的Java代码程序的运行速度接近于C语言程序。

静态编译

静态编译器在运行之前将Java字节码转换为依赖于平台的C语言代码。然后标准的C编译器为目标平台将C代码编译为一个可执行文件。这个方法更加适合于那些修改不频繁的Java应用程序。这种方法充分利用了在C语言中的成熟和与平台相关的高效的编译技术。

OracleJava核心类库均使用静态编译的方法:ORB以及JDBC代码是被编译为本地形式。静态方法对于oracle所支持的所有平台均使用,而JIT方法则需要为每个平台编写和维护与处理器相关的低阶代码。开发者可以对自己编写的Java代码使用JIT的编译技术。

 

动态的类加载

Java的另一种重要特性是就是动态类的加载。当Java程序运行时,类加载器从磁盘中加载类(并且将这些类放进JVM指定的内存结构中进行解释操作)类的加载器将类放置在CLASSPATH路径下,并且在程序执行期间加载这些类。这种方法,对于applet程序来说工作正常,但是在服务器端会产生下面的问题:

问题

描述

解决方案

可预测性

在第一次执行程序时,类加载操作比较严重。一个简单的程序能够引起oracleJVM来加载许多核心的类来支持执行程序的需要。一个程序员不能简单的预言或者决定需要加载类的数量。

OracleJVM动态地加载类,与其他Java虚拟机加载类的方法一样。同样遇到一次类加载速度的打击。但是因为类是被加载到共享池中,这些类的其他用户可以不需要再次进行类加载的工作这些用户只需使用同样的已经被加载的类。

可靠性

动态加载类的优势是支持程序更新。比如:你可以在服务器端更新类,并且下载程序以及加载程序的客户端能够在下次使用程序时发现程序需要更新。服务器端程序最注重可靠性。作为一个开发者,必须知道每个客户端运行程序的配置情况。开发者不希望客户端加载一些开发者不想加载的类。

Oracle将上传以及解析操作在运行时从类加载操作工作中独立出来。用户可以使用loadJava工具上传开发出来的Java代码到服务器上。不是使用CLASSPASH,而是在安装时指定解析器。解析器类似于CLASSPASH,但是解析器让你指定类所在的方案对象。将解析和类加载分离意味着开发者可以知道用户运行的是什么程序。

 

OracleJava应用程序策略

Java重要的吸引力是应用比较广泛并且开发Java应用程序的程序员的日夜增长。Oracle为企业应用程序开发者提供了点对点的Java解决方案,从创建,,部署,以及管理Java应用程序。这个整个的解决方案是由客户端,服务端,以及服务端程序接口,支持Java开发的工具以及在oracle数据库服务端集成的java虚拟机。所有这些产品是Java标准是兼容的。

除了oracleJVMJava程序环境中是由下面组成:

*Java存储过程类似于PL/SQLJava存储过程紧紧地与PL/SQL集成。用户可以从PL/SQL包中调用Java存储过程;用户也可以从Java存储过程中调用PL/SQL存储过程。

*SQL数据能够通过JDBC程序接口被访问

*用于帮助开发,类加载以及类管理的工具以及脚本

这部分包含下面的内容:

*Java存储过程

*PL/SQLoracle功能集成

*JDBC

*JPublisher

*Java消息服务

 

Java存储过程

一个Java存储过程是用户用Java编写的运行于服务器端的程序,与PL/SQL存储过程完全相同。用户可以使用象SQL*PLUS类似的产品直接调用Java存储过程,或者使用触发器间接调用。用户可以通过任意的oracle Net客户端(OCI,预编译器,或者JDBC)来调用Java存储过程。

除此之外,用户能够使用Java来开发强大的独立于PL/SQL的程序。Oracle 提供了与标准完全兼容的Java程序语言和JVM的实现。

 

PL/SQLoracle的功能集成

用户可以从Java中调用存在的PL/SQL程序并且可以从PL/SQL中调用Java存储程序。这种解决方案保护和利用已经存在的投资,同时也充分利用了基于JavaInternet计算优势。

 

JDBC

Java数据库连接(JDBC)对于Java开发员来说是一个应用程序接口,主要用于访问SQL数据。JDBC在客户端和服务端均可以使用,所以用户可以在任意一端部署同样的代码。

OracleJDBC允许Java程序通过动态SQL语句对定义在数据库中的对象以及集合类型的访问。动态SQL意味着将要被嵌入的SQL语句在应用程序运行之前是未知的,并且需要输入条件来构建执行语句。JDBC通过默认的或者子定义的映射来将定义在数据库中的类型转换为Java类,并且JDBC也能够使用户能够在数据库操作级来监控,跟踪以及分析JavaJ2EE应用程序的资源消耗情况。

可心的Java类库只提供一个JDBC APIJDBC被设计用来允许第三方开发商提供驱动程序,该驱动程序是为特定的数据库提供必要的规范说明。Oracle提供了下面的三种不同的JDBC驱动:

驱动

描述

JDBC瘦客户驱动程序

用户可以使用JDBC瘦客户驱动程序来编写纯Java应用程序和applets,这些应用程序可以访问oracleSQL数据。JDBC瘦驱动程序尤其适合于基于Web网页的应用程序和applets,因为用户可以从Web页面动态下载,就如任意其他的Java applet

JDBC OCI驱动程序

JDBC OCI驱动程序可以访问位于客户端或者中间件中的oracle特定的本地代码,与JDBC瘦客户驱动程序相比提供了大量的更多的功能集以及更好的性能,但是其成本是容量很大并且需要在客户端安装。

JDBC服务端内部驱动程序

Java代码运行在服务端时,Oracle使用服务端内部驱动程序。JDBC服务端内部驱动允许运行在服务端的JVMJava应用程序通过JDBC访问本地定义的数据(也就是说,在同一个计算机上并且是在同一个进程中)。该种驱动程序提供了更好的性能是因为该种驱动可以直接使用oracleRDBMS类库,而不需要在Java代码和SQL数据之间建立网络连接。通过在服务器端以及在客户端支持相同的Java-SQL接口,当在部署时oracle不需要用户修改代码。

 

SQLJ

SQLJ允许开发者在Java程序中使用对象类型。开发者可以使用JPublisher来将oracle对象和集合类型映射到应用程序所使用的Java类。

SQLJ使用SQL语句嵌入到Java代码中去的方法来访问服务器端的对象。SQLJ能够对SQL语句中的对象类型和集合类型进行编译时类型检查。语法是基于ANSI标准。

用户可以指定Java类作为SQL自定义的对象类型。开发者可以定义这个SQLJ对象类型的列和行。用户能够查询和操纵这个SQLJ类型的对象,其操作方法就和操作SQL对象相同。此外,用户能够做下面的操作:

*使一个类的静态字段在SQL语句中可见

*允许用户调用Java类的构造体

*维护Java类与其相对应的类型依赖关系

 

JPublisher

Java PublisherJPublisher)是一个工具,全部是用Java编写,在用户的Java程序中JPublisher工具会产生Java类来代表下面用户自定义的数据库实体:

*SQL对象类型

*对象引用类型(“REF类型”)

*SQL集合类型(VARRAY类型或者嵌入表类型)

*PL/SQL

JPublisher工具使用户能够指定并且自定义这些数据库实体与Java类的映射。

 

Java消息服务

Java消息服务(JMS)  SUN 微系统和 OracleIBM,及其他厂商制定的消息系统标准。这个标准为JMS应用程序定义了接口集合并且指定了JMS供应商需要实现的行为。JMS提供了一个基于标准的API,用户可以在企业内部,以及在企业与客户和合作伙伴之间能够异步地进行业务事件的交换。

OracleJMS是基于JMS标准以及oracle数据流的一个Java API。多客户应用程序能够通过中央JMS提供商(oracle数据流)发送并且接受任何类型的消息。JMS客户端是由Java应用程序以及一个实现了JMS接口以及能够与oracle数据流通信的消息服务客户运行库组成。

Oracle JMS支持标准的JMS接口,并且能够扩展为支持其他的不属于标准范围内的流的特性。用户可以使用JMS来对oracle数据流队列中的消息进行入队出队操作。OracleJMS包括标准的特性:

*使用队列进行点对点通信

*根据主题进行发布-订阅式通信

*同步或异步的消息交换

*根据主题对消息进行路由

 

Oracle数据流也提供对标准JMS特性的扩展:

*使用接受点列表来定义接受消息的应用程序,实现一点对多点的通信

*管理性API,用于创建队列表,队列以及主题

*在不同的数据库上的队列之间进行自动的消息传播,使应用程序能够使用远程订阅者

*支持事务性会话,允许在一个事务中进行JSM以及SQL操作

*消息被使用后可以设定消息保留周期

*异常处理

*可以设定消息可见延迟

抱歉!评论已关闭.