使用SQLJ编写存储过程
来源:互联网 发布:阿里云怎么用 编辑:程序博客网 时间:2024/06/05 11:42
1. 编写一个SQLJ存储过程
4. 运行过程
5. 和PL/SQL相对应的过程比较结果
PL/SQL存储过程
在例子中,ValidTransaction包含12个时期的数据,共有一百二十万行。 在ValidTransaction表中的每一行,Classification表分别有10行与之对应,所以就共有一千二百万行数据。清除一个指定月份的Classification数据意味着从Classification表中删除1百万行数据。
DeleteClassification过程的代码使用了一些Oracle 8i PL/SQL中的新的特性,象BULK BINDS和BULK COLLECT,用来改善事务的执行性能并增加你在事务中可交付的数据数量,从而减少事务的数目并且降低发生ORA - 01555错误的可能性。 BULK COLLECT子句能使整个TransactToReset游标一步就被取出到v_TransactionId PL/SQL表中。 然后游标立即被关闭以避免交叉获取错误,这样也同样减少ORA - 01555错误的发生。
最后,这个过程计算删除行数的百分比。 如果结果超过了限度,主关键字索引可能就会被损坏而且你还可能要重建它。
代码段1 演示了DeleteClassification存储过程的PL/SQL版本。
创建SQLJ存储过程将要编写服务器端SQLJ代码,另外将在一台客户机上执行编译过程。这个途径提供翻译SQLJ代码的最大灵活性--选项设置和错误处理在客户机上比在服务器上更方便。
开发一个SQLJ存储过程由五个步骤组成:
1. 使用Java类的静态方法创建一个SQLJ源文件,后面将要把这个源文件通过SQL封装器与PL/SQL环境合并起来。
2. 把这个SQLJ源文件编译成一个Java类或者一组Java类。把所有的类合并成一个.jar文件。
4. 为存储的Java过程/函数创建一个PL/SQL封装器。
使用import语句启动PipelineReset.sqlj文件。 只导入你计划在你的类中使用的Java
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Iterator;
SQLJ运行时刻程序包可在JServer Java虚拟机( JVM)中找到。 还有,你不必编写创建到数据库的连接的代码了,因为JServer本身带有到数据库服务器的隐含的连接。由于你将在客户机上编译源代码,所以必须包括下列三个import语句:
import sqlj.runtime.ref.DefaultContext;
import sqlj.runtime.ExecutionContext;
接下来,需要声明迭代程序类。在迭代程序类声明中定义了SQLJ为你构造的Java类。你必须把SQLJ迭代程序声明和连接上下文说明放在你的SQLJ源文件里的Java类的顶端,紧接着import语句之后。 下列三个迭代程序声明提供PL/SQL版的三个游标函数:
(Timestamp startDate, Timestamp endDate);
#sql iterator ValidTransactions
(Long transactionId);
#sql iterator ClassificationCount
(long);
使用下面三个参数定义PipelineReset.java类的静态DeleteClassification方法:
public static void DeleteClassification(
String periodName,
int commitBatchSize,
int percentageDeleted) throws SQLException {
...
}
}
现在我们把代码放入方法中。 首先你需要实例化一个迭代程序对象决定具体时期的起始和结束时间。 使用periodname参数:
Timestamp endDate = null;
Timestamp startDate = null;
#sql dateIter = { select startDate,
endDate
from Period
where description = :periodName };
if (dateIter.next()) {
startDate = dateIter.startDate();
endDate = dateIter.endDate();
};
dateIter.close();
#sql vtIter = { select T.TransactionId
from ValidTransaction T
where T.TransactionDate >= :startDate
and T.TransactionDate <= :endDate
and exists (select '1'
from Classification C
where C.TransactionId = T.TransactionId) };
ArrayList vtIdList = new ArrayList();
while (vtIter.next()) {
vtIdList.add((Long) vtIter.TransactionId());
}
vtIter.close();
现在在vtIDList对象中循环,删除Classification中TransactionId每个值所对应的行。
ClassificationCount countIter;
long vDeletedRows = 0;
long vTotalRows = 0;
int vCount = 0;
if (vtIdList.size() > 0) {
#sql countIter = { select count(*) from Classification };
#sql { fetch : countIter into :vTotalRows };
countIter.close();
Iterator itr = vtIdList.iterator();
while (itr.hasNext()) {
vCount++;
#sql [ec] { delete from Classification
where TransactionId = :((Long) itr.next()) };
vDeletedRows = vDeletedRows + ec.getUpdateCount();
if ((vCount % commitBatchSize) == 0) {
#sql [ec] { commit };
}
}
#sql [ec] { commit };
}
最后,你必须决定你是否要重建索引。 从你的SQLJ代码中调用相同的RebuildIndex PL/SQL存储过程:
percentageDeleted ) {
#sql [ec] {call RebuildIndex('CLASSIFICATION_PK_IND',
'parallel nologging compute statistics')};
}
第二步: 翻译并编译SQLJ源文件
本文中不可能包含所有的SQLJ实用命令行选项,但是如果你需要更多信息,请参阅相应的Oracle文档。
我发现把下面的信息放入名为Translator.properties的属性文件中会很方便:
sqlj.user=scott
sqlj.password=tiger
sqlj.driver=oracle.jdbc.driver.OracleDriver
sqlj.url=jdbc:oracle:oci8:@ORCL
sqlj.warn=verbose
sqlj.linemap
你可以在OracleHome/sqlj/demo目录中找到一个样本sqlj.properties文件。下面给出了用来翻译和编译SQLJ源文件的命令:
在本例中,用六个类文件结束:主要的PipelineReset.class,三个迭代程序类( StartEndDate.class,ValidTransactions.class和ClassificationCount.class)以及配置类( PipelineReset_SJProfile.class和PipelineReset_SJProfileKeys.class)。使用下列命令把它们封装到一个PipelineReset.jar Java压缩文件中:
现在需要把生成的类载入数据库中。
Oracle提供了一个默认的使用Oracle JDBC OCI8驱动程序的loadjava实用程序来完成连接。下面就是用一个ORCL数据库和一个用户scott/tiger做为参数来使用这个实用程序的语法:
还可以指定Oracle JDBC瘦驱动程序:
使用- resolve标志直接地分析类的引用而不是等待每个类被第一次调用。
status
from User_Objects
where object_type = 'JAVA CLASS'
order by object_name;
------------------------------ -------
ClassificationCount VALID
PipelineReset VALID
PipelineReset_SJProfile0 VALID
PipelineReset_SJProfileKeys VALID
StartEndDate VALID
ValidTransactions VALID
6 rows selected.
正如所见,你所有的Java类都被成功地载入数据库中了。
第四步:为Java存储过程创建PL/SQL封装程序
即使Java代码已经在数据库中了,但是它还是不能真正的可用。 Oracle数据库
下面的脚本将创建PipelineResetFull程序包的一个JDeleteClassification过程。 这个过程是PipelineReset Java类的DeleteClassification静态方法的PL/SQL封装程序。
procedure JDeleteClassification
(periodName in varchar2,
commitBatchSize in number,
percentDeleted in number);
end PipelineResetFull;
/
create or replace package body PipelineResetFull as
procedure JDeleteClassification
(periodName in varchar2,
commitBatchSize in number,
percentDeleted in number)
as
language java
name 'PipelineReset.DeleteClassification(java.lang.String,
int,
int)';
end PipelineResetFull;
/
例如:下列的语法是错误的:
name 'PipelineReset.DeleteClassification(String,
int,
int)';
...
它能够编译,但是将抛出运行时间异常:
ORA-29531: no method DeleteClassification in class PipelineReset
这是怎么发生的呢?DeleteClassification不就在PipelineReset类中吗? 事实上,它是这个类中的唯一的方法!
Oracle不能匹配PL/SQL封装程序中的DeleteClassification方法与一个实际类的方法。 在这种情况下,你必须明确地指定一个完全符合规格的类的路径,除非它是一个基类,就像在我们例子中的int Java类型。
在数据库中发布Java代码之后,我们就会发现在PL/SQL和Java过程之间就没有用法差异了。可以使用下列代码从SQL * Plus中调用并测试PL/SQL和Java代码:
DeleteClassification('January 1999', 10000, 10);
End;
/
begin
PipelineResetFull.JDeleteClassification('January 1999', 10000, 10);
end;
/
现在我们甚至不能分辩出哪个是Java过程,因为它已经完全和PL/SQL环境整合起来了。
SQLJ:一个有价值的数据库开发解决方案
我认为SQLJ是一个非常有价值的数据库开发解决方案,将不断的发展和成熟。 ORACLE
代码段1
create or replace procedure DeleteClassification
(pPeriodName in varchar2: = null,
pCommitBatchSize in integer := 10000,
pPercentDeleted in integer:= 10)
as
vPeriodSeq pls_integer;
vPeriodStart date;
vPeriodEnd date;
vBeginIndex pls_integer := 0;
vEndIndex pls_integer := 0;
vTransactionIdCount integer := 0;
vDeletedRows integer := 0;
vTotalRows integer := 0;
vPercentageDeleted pls_integer := 0;
cursor csrPeriodData (pPeriodDescription Period.Description%type) is
select PeriodSeq,
StartDate,
EndDate
from Period
where Description = pPeriodDescription;
type tTransactionId is
table of ValidTransaction.TransactionId%type
index by binary_integer;
vTransactionId tTransactionId;
cursor csrTransactToReset (pStartDate IN date, pEndDate IN date) IS
select T.TransactionId
from ValidTransaction T
where T.TransactionDate >= pStartDate
and T.TransactionDate <= pEndDate
and exists
(select '1'
from Classification C
where C.TransactionId = T.TransactionId);
cursor csrClassificationCount is
select count(*)
from Classification;
begin
if pPeriodName is null
then
RAISE_APPLICATION_ERROR(-20301,
'You must supply a valid period.');
end if;
open csrPeriodData(pPeriodName);
fetch csrPeriodData into vPeriodSeq, vPeriodStart, vPeriodEnd;
if csrPeriodData%notfound
then
close csrPeriodData;
RAISE_APPLICATION_ERROR(-20302,
'You must supply a valid period. ' ||
'Please use the description field of the period.');
end if;
close csrPeriodData;
open csrTransactToReset (vPeriodStart, vPeriodEnd);
fetch csrTransactToReset bulk collect into vTransactionId;
close csrTransactToReset;
vTransactionIdCount := vTransactionId.count;
if vTransactionIdCount > 0
then
open csrClassificationCount;
fetch csrClassificationCount into vTotalRows;
close csrClassificationCount;
while vEndIndex < vTransactionIdCount
loop
vBeginIndex := vEndIndex + 1;
if vEndIndex + pCommitBatchSize < vTransactionIdCount
then
vEndIndex := vEndIndex + pCommitBatchSize;
else
vEndIndex := vTransactionIdCount;
end if;
forall nIndex in vBeginIndex..vEndIndex
delete from Classification
where TransactionId = vTransactionId(nIndex);
vDeletedRows := vDeletedRows + sql%rowcount;
commit;
end loop;
vPercentageDeleted := round((vDeletedRows / vTotalRows) * 100);
if vPercentageDeleted >= p_percentDeleted
then
RebuildIndex('CLASSIFICATION_PK_IND',
'parallel nologging compute statistics');
end if;
end if;
end DeleteClassification;
代码段2:
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Iterator;
import oracle.jdbc.driver.OracleConnection;
import sqlj.runtime.ref.DefaultContext;
import sqlj.runtime.ExecutionContext;
#sql iterator StartEndDate (Timestamp startDate, Timestamp endDate) ;
#sql iterator ValidTransactions (Long transactionId) ;
#sql iterator ClassificationCount (long) ;
public class PipelineReset
{
public static void DeleteClassification(
String periodName,
int commitBatchSize,
int percentageDeleted) throws SQLException {
StartEndDate dateIter;
ValidTransactions vtIter;
ClassificationCount countIter;
Timestamp endDate = null;
Timestamp startDate = null;
int vCount = 0;
long vDeletedRows = 0;
long vTotalRows = 0;
#sql dateIter = { select startDate,
endDate
from Period
where description = :periodName };
long startTime = System.currentTimeMillis();
if (dateIter.next()) {
startDate = dateIter.startDate();
endDate = dateIter.endDate();
};
dateIter.close();
#sql vtIter = { select T.TransactionId
from ValidTransaction T
where T.TransactionDate >= :startDate
and T.TransactionDate <= :endDate
and exists (select '1'
from Classification C
where C.TransactionId = T.TransactionId) };
fetched from vtIter iterator */
ArrayList vtIdList = new ArrayList();
while (vtIter.next()) {
vtIdList.add((Long) vtIter.TransactionId());
}
vtIter.close();
ExecutionContext ec =
DefaultContext.getDefaultContext().getExecutionContext();
if (vtIdList.size() > 0) {
#sql countIter = { select count(*) from Classification };
#sql { fetch : countIter into :vTotalRows };
countIter.close();
Iterator itr = vtIdList.iterator();
while (itr.hasNext()) {
vCount++;
#sql [ec] { delete from Classification
where TransactionId = :((Long) itr.next()) };
vDeletedRows = vDeletedRows + ec.getUpdateCount();
if ((vCount % commitBatchSize) == 0) {
#sql [ec] { commit };
}
}
#sql [ec] { commit };
}
if ((((float) vDeletedRows / (float) vTotalRows) * 100) >=
percentageDeleted ) {
#sql [ec] { call RebuildIndex('CLASSIFICATION_PK_IND',
'parallel nologging compute statistics') };
}
}
long endTime = System.currentTimeMillis();
System.out.println("Total time : " +
((endTime - startTime) / 1000) + " sec.");
}
}
- 使用SQLJ编写存储过程
- 使用SQLJ编写存储过程
- 【转载】Java JDBC 执行 DDL 和 SQLJ 存储过程
- 技巧:使用 C# 编写扩展存储过程
- 使用VS.NET2003编写存储过程
- 使用VS.NET2003编写存储过程
- 使用VS.NET2003编写存储过程
- 使用VS.NET2003编写存储过程
- 使用VS.NET2003编写存储过程
- 使用Java编写oracle存储过程
- 使用VS.NET2003编写存储过程
- 技巧:使用 C# 编写扩展存储过程
- 使用Java编写oracle存储过程
- 使用Java编写Oracle存储过程
- 使用oracle存储过程编写分页
- 编写CLR存储过程中使用SqlDataRecord
- MySQL存储过程的编写与使用
- 开始编写存储过程
- 向 RCP 致敬
- 函数参数栈传递
- 学习Eclipse RCP之Hello World
- [微软公司招聘题目]狗的问题
- 使用links方式安装Eclipse插件
- 使用SQLJ编写存储过程
- Understanding Layouts in SWT
- 正则表达式30分钟入门教程
- SQL Server 2005 Integration Services (SSIS)数据源之MySQL
- .net面试题1(转)
- 代码级配置管理VS产品级配置管理
- 删除最后一个字符的方法。
- 手机操作系统实战DotNet for Symbian平台
- .NET求职笔试题目(续) 转载