概述
PL/SQL中的過程和函數(shù)(通常稱為子程序)是PL/SQL塊的一種特殊的類型,這種類型的子程序可以以編譯的形式存放在數(shù)據(jù)庫中,并為后續(xù)的程序塊調(diào)用。
相同點: 完成特定功能的程序
不同點:是否用return語句返回值。
舉個例子:
create or replace procedure PrintStudents(p_staffName in xgj_test.username%type) as
cursor c_testData is
select t.sal, t.comm from xgj_test t where t.username = p_staffName;
begin
for v_info in c_testData loop
DBMS_OUTPUT.PUT_LINE(v_info.sal || ' ' || v_info.comm);
end loop;
end PrintStudents;
一旦創(chuàng)建了改程序并將其存儲在數(shù)據(jù)庫中,就可以使用如下的方式調(diào)用該過程
begin
PrintStudents('Computer Science');
PrintStudents('Match');
end;
/
或者
exec PrintStudents('Computer Science');
exec PrintStudents('Match');
在命令窗口中:
![](http://img.jbzj.com/file_images/article/201611/20161115160934759.png?2016101516947)
在pl/sql工具的sql窗口中: ![](http://img.jbzj.com/file_images/article/201611/20161115160955120.png?2016101516105)
存儲過程的創(chuàng)建和調(diào)用
基本語法
create [ or replace] procedure procedure_name
[( argument [ {IN | OUT | IN OUT }] type,
......
argument [ {IN | OUT | IN OUT }] type ) ] { IS | AS}
procedure_body
無參的存儲過程
/**
無參數(shù)的存過
打印hello world
調(diào)用存儲過程:
1. exec sayhelloworld();
2 begin
sayhelloworld();
end;
/
*/
create or replace procedure sayhelloworld
as
--說明部分
begin
dbms_output.put_line('hello world');
end sayhelloworld;
調(diào)用過程:
SQL> set serveroutput on ;
SQL> exec sayhelloworld();
hello world
PL/SQL procedure successfully completed
SQL> begin
2 sayhelloworld();
3 sayhelloworld();
4 end;
5 /
hello world
hello world
PL/SQL procedure successfully completed
帶參數(shù)的存儲過程
/**
創(chuàng)建一個帶參數(shù)的存儲過程
給指定的員工增加工資,并打印增長前后的工資
*/
create or replace procedure addSalary(staffName in xgj_test.username%type )
as
--定義一個變量保存調(diào)整之前的薪水
oldSalary xgj_test.sal%type;
begin
--查詢員工漲之前的薪水
select t.sal into oldSalary from xgj_test t where t.username=staffName;
--調(diào)整薪水
update xgj_test t set t.sal = sal+1000 where t.username=staffName ;
--輸出
dbms_output.put_line('調(diào)整之前的薪水:'|| oldSalary || ' ,調(diào)整之后的薪水:' || (oldSalary + 1000));
end addSalary;
可以看到,update語句之后并沒有commit的操作。
一般來講為了保證事務(wù)的一致性,由調(diào)用者來提交比較合適,當(dāng)然了是需要區(qū)分具體的業(yè)務(wù)需求的~
begin
addSalary('xiao');
addSalary('gong');
commit ;
end ;
/
存儲函數(shù)
基本語法
create [ or replace] function function_name
[( argument [ {IN | OUT | IN OUT }] type,
......
argument [ {IN | OUT | IN OUT }] type ) ]
RETURN { IS | AS}
function_body
其中 return子句是必須存在的,一個函數(shù)如果沒有執(zhí)行return就結(jié)束將發(fā)生錯誤,這一點和存過有說不同。
存儲函數(shù)
準(zhǔn)備的數(shù)據(jù)如下:
![](http://img.jbzj.com/file_images/article/201611/20161115161011623.png?20161015161020)
/**
查詢員工的年薪 (月工資*12 + 獎金)
*/
create or replace function querySalaryInCome(staffName in varchar2)
return number as
--定義變量保存員工的工資和獎金
pSalary xgj_test.sal%type;
pComm xgj_test.comm%type;
begin
--查詢員工的工資和獎金
select t.sal, t.comm
into pSalary, pComm
from xgj_test t
where t.username = staffName;
--直接返回年薪
return pSalary * 12 + pComm;
end querySalaryInCome;
![](http://img.jbzj.com/file_images/article/201611/20161115161413692.png?20161015161436)
存在一個問題,當(dāng)獎金為空的時候,算出來的年收入竟然是空的。
因為 如果一個表達式中有空值,那么這個表達式的結(jié)果即為空值。
所以我們需要對空值進行處理, 使用nvl函數(shù)即可。
最后修改后的function為
create or replace function querySalaryInCome(staffName in varchar2)
return number as
--定義變量保存員工的工資和獎金
pSalary xgj_test.sal%type;
pComm xgj_test.comm%type;
begin
--查詢員工的工資和獎金
select t.sal, t.comm
into pSalary, pComm
from xgj_test t
where t.username = staffName;
--直接返回年薪
return pSalary * 12 + nvl(pComm,0);
end querySalaryInCome;
out參數(shù)
一般來講,存儲過程和存儲函數(shù)的區(qū)別在于存儲函數(shù)可以有一個返回值,而存儲過程沒有返回值。
- 存儲過程和存儲函數(shù)都可以有out參數(shù)
- 存儲過程和存儲函數(shù)都可以有多個out參數(shù)
- 存儲過程可以通過out參數(shù)實現(xiàn)返回值
那我們?nèi)绾芜x擇存儲過程和存儲函數(shù)呢?
原則:
如果只有一個返回值,用存儲函數(shù),否則(即沒有返回值或者有多個返回值)使用存儲過程。
/**
根據(jù)員工姓名,查詢員工的全部信息
*/
create or replace procedure QueryStaffInfo(staffName in xgj_test.username%type,
pSal out number,
pComm out xgj_test.comm%type,
pJob out xgj_test.job%type)
is
begin
--查詢該員工的薪資,獎金和職位
select t.sal,t.comm,t.job into pSal,pComm,pJob from xgj_test t where t.username=staffName;
end QueryStaffInfo;
![](http://img.jbzj.com/file_images/article/201611/20161115161551939.png?2016101516160)
先拋出兩個思考問題:
- 查詢員工的所有信息–> out參數(shù)太多怎么辦?
- 查詢某個部門中所有員工的信息–> out中返回集合?
后面會講到如何解決? 總不能一個個的寫out吧~
在應(yīng)用中訪問存儲過程和存儲函數(shù)
概述
我們使用Java程序連接Oracle數(shù)據(jù)庫。
使用jar: ojdbc14.jar
關(guān)于oracle官方提供的幾個jar的區(qū)別
- classes12.jar (1,600,090 bytes) - for use with JDK 1.2 and JDK 1.3
- classes12_g.jar (2,044,594 bytes) - same as classes12.jar, except that classes were compiled with “javac -g” and contain some tracing information.
- classes12dms.jar (1,607,745 bytes) - same as classes12.jar, except that it contains additional code`to support Oracle Dynamic Monitoring Service.
- classes12dms_g.jar (2,052,968 bytes) - same as classes12dms.jar except that classes were compiled with “javac -g” and contain some tracing information.
- ojdbc14.jar (1,545,954 bytes) - classes for use with JDK 1.4 and 1.5
- ojdbc14_g.jar (1,938,906 bytes) - same as ojdbc14.jar, except that classes were compiled with “javac -g” and contain some tracing information.
- ojdbc14dms.jar (1,553,561 bytes) - same as ojdbc14.jar, except that it contains additional code`to support Oracle Dynamic Monitoring Service.
- ojdbc14dms_g.jar (1,947,136 bytes) - same as ojdbc14dms.jar, except that classes were compiled with “javac -g” and contain some tracing information.
工程目錄如下:
![](http://img.jbzj.com/file_images/article/201611/20161115161652343.png?2016101516171)
簡單的寫下獲取數(shù)據(jù)庫連接的工具類
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DBUtils {
// 設(shè)定數(shù)據(jù)庫驅(qū)動,數(shù)據(jù)庫連接地址端口名稱,用戶名,密碼
private static final String driver = "oracle.jdbc.driver.OracleDriver";
private static final String url = "jdbc:oracle:thin:@ip:xxxx";
private static final String username = "xxxx";
private static final String password = "xxxx";
/**
* 注冊數(shù)據(jù)庫驅(qū)動
*/
static {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError(e.getMessage());
}
}
/**
* 獲取數(shù)據(jù)庫連接
*/
public static Connection getConnection() {
try {
Connection connection = DriverManager.getConnection(url, username, password);
// 成功,返回connection
return connection;
} catch (SQLException e) {
e.printStackTrace();
}
// 獲取失敗,返回null
return null;
}
/**
* 釋放連接
*/
public static void cleanup(Connection conn, Statement st, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
rs = null;
}
}
if (st != null) {
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
st = null;
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
conn = null;
}
}
}
}
在應(yīng)用程序中訪問存儲過程
根據(jù)官方提供的API,我們可以看到:
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import org.junit.Test;
import com.turing.oracle.dbutil.DBUtils;
import oracle.jdbc.OracleTypes;
public class TestProcedure {
@Test
public void callProcedure(){
// {call procedure-name>[(arg1>,arg2>, ...)]}
Connection conn = null ;
CallableStatement callableStatement = null ;
/**
*
根據(jù)員工姓名,查詢員工的全部信息
create or replace procedure QueryStaffInfo(staffName in xgj_test.username%type,
pSal out number,
pComm out xgj_test.comm%type,
pJob out xgj_test.job%type)
is
begin
--查詢該員工的薪資,獎金和職位
select t.sal,t.comm,t.job into pSal,pComm,pJob from xgj_test t where t.username=staffName;
end QueryStaffInfo;
*/
// 我們可以看到該存過 4個參數(shù) 1個入?yún)?3個出參
String sql = "{call QueryStaffInfo(?,?,?,?)}";
try {
// 獲取連接
conn = DBUtils.getConnection();
// 通過連接獲取到CallableStatement
callableStatement = conn.prepareCall(sql);
// 對于in 參數(shù),需要賦值
callableStatement.setString(1, "xiao");
// 對于out 參數(shù),需要聲明
callableStatement.registerOutParameter(2, OracleTypes.NUMBER); // 第二個 ?
callableStatement.registerOutParameter(3, OracleTypes.NUMBER);// 第三個 ?
callableStatement.registerOutParameter(4, OracleTypes.VARCHAR);// 第四個 ?
// 執(zhí)行調(diào)用
callableStatement.execute();
// 取出結(jié)果
int salary = callableStatement.getInt(2);
int comm = callableStatement.getInt(3);
String job = callableStatement.getString(3);
System.out.println(salary + "\t" + comm + "\t" + job);
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtils.cleanup(conn, callableStatement, null);
}
}
}
在應(yīng)用程序中訪問存儲函數(shù)
根據(jù)官方提供的API,我們可以看到:![](http://img.jbzj.com/file_images/article/201611/20161115161824356.png?20161015161832)
import java.sql.CallableStatement;
import java.sql.Connection;
import org.junit.Test;
import com.turing.oracle.dbutil.DBUtils;
import oracle.jdbc.OracleTypes;
public class TestFuction {
@Test
public void callFuction(){
//{?= call procedure-name>[(arg1>,arg2>, ...)]}
Connection conn = null;
CallableStatement call = null;
/**
* create or replace function querySalaryInCome(staffName in varchar2)
return number as
--定義變量保存員工的工資和獎金
pSalary xgj_test.sal%type;
pComm xgj_test.comm%type;
begin
--查詢員工的工資和獎金
select t.sal, t.comm
into pSalary, pComm
from xgj_test t
where t.username = staffName;
--直接返回年薪
return pSalary * 12 + nvl(pComm,0);
end querySalaryInCome;
*/
String sql = "{?=call querySalaryInCome(?)}";
try {
// 獲取連接
conn = DBUtils.getConnection();
// 通過conn獲取CallableStatement
call = conn.prepareCall(sql);
// out 參數(shù),需要聲明
call.registerOutParameter(1, OracleTypes.NUMBER);
// in 參數(shù),需要賦值
call.setString(2, "gong");
// 執(zhí)行
call.execute();
// 取出返回值 第一個?的值
double income = call.getDouble(1);
System.out.println("該員工的年收入:" + income);
} catch (Exception e) {
e.printStackTrace();
}finally {
DBUtils.cleanup(conn, call, null);
}
}
}
在out參數(shù)中訪問光標(biāo)
在out參數(shù)中使用光標(biāo)
我們之前拋出的兩個思考問題:
- 查詢員工的所有信息–> out參數(shù)太多怎么辦?
- 查詢某個部門中所有員工的信息–> out中返回集合?
我們可以通過返回Cursor的方式來實現(xiàn)。
在out參數(shù)中使用光標(biāo) 的步驟:
包頭:
create or replace package MyPackage is
-- Author : ADMINISTRATOR
-- Created : 2016-6-4 18:10:42
-- Purpose :
-- 使用type關(guān)鍵字 is ref cursor說明是cursor類型
type staffCursor is ref cursor;
procedure queryStaffJob(pJob in xgj_test.job%type,
jobStaffList out staffCursor);
end MyPackage;
創(chuàng)建完包頭之后,創(chuàng)建包體,包體需要實現(xiàn)包頭中聲明的所有方法。
包體
create or replace package body MyPackage is
procedure queryStaffJob(pJob in xgj_test.job%type,
jobStaffList out staffCursor)
as
begin
open jobStaffList for select * from xgj_test t where t.job=pJob;
end queryStaffJob;
end MyPackage;
事實上,通過plsql工具創(chuàng)建包頭,編譯后,包體的框架就會自動的生成了。
在應(yīng)用程序中訪問包下的存儲過程
在應(yīng)用程序中訪問包下的存儲過程
在應(yīng)用程序中訪問包下的存儲過程 ,需要帶包名
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import org.junit.Test;
import com.turing.oracle.dbutil.DBUtils;
import oracle.jdbc.OracleTypes;
import oracle.jdbc.driver.OracleCallableStatement;
public class TestCursor {
@Test
public void testCursor(){
/**
*
* create or replace package MyPackage is
type staffCursor is ref cursor;
procedure queryStaffJob(pJob in xgj_test.job%type,
jobStaffList out staffCursor);
end MyPackage;
*/
String sql = "{call MyPackage.queryStaffJob(?,?)}" ;
Connection conn = null;
CallableStatement call = null ;
ResultSet rs = null;
try {
// 獲取數(shù)據(jù)庫連接
conn = DBUtils.getConnection();
// 通過conn創(chuàng)建CallableStatemet
call = conn.prepareCall(sql);
// in 參數(shù) 需要賦值
call.setString(1, "Staff");
// out 參數(shù)需要聲明
call.registerOutParameter(2, OracleTypes.CURSOR);
// 執(zhí)行調(diào)用
call.execute();
// 獲取返回值
rs = ((OracleCallableStatement)call).getCursor(2);
while(rs.next()){
// 取出值
String username = rs.getString("username");
double sal = rs.getDouble("sal");
double comm = rs.getDouble("comm");
System.out.println("username:" + username + "\t sal:" + sal + "\t comm:" + comm);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
DBUtils.cleanup(conn, call, rs);
}
}
}
原文鏈接:http://blog.csdn.net/yangshangwei/article/details/51581952
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
您可能感興趣的文章:- oracle 存儲過程詳細(xì)介紹(創(chuàng)建,刪除存儲過程,參數(shù)傳遞等)
- Oracle存儲過程返回游標(biāo)實例詳解
- oracle 在一個存儲過程中調(diào)用另一個返回游標(biāo)的存儲過程
- Oracle存儲過程入門學(xué)習(xí)基本語法
- Oracle中 關(guān)于數(shù)據(jù)庫存儲過程和存儲函數(shù)的使用
- oracle如何恢復(fù)被覆蓋的存儲過程
- oracle數(shù)據(jù)庫中查看系統(tǒng)存儲過程的方法
- oracle 存儲過程和函數(shù)例子
- Oracle 存儲過程總結(jié) 二、字符串處理相關(guān)函數(shù)
- Oracle存儲過程和存儲函數(shù)創(chuàng)建方法(詳解)
- Oracle學(xué)習(xí)記錄之使用自定義函數(shù)和觸發(fā)器實現(xiàn)主鍵動態(tài)生成
- oracle 存儲過程、函數(shù)和觸發(fā)器用法實例詳解