PL/SQL (Procedural Language/SQL) 是 Oracle 在标准的 SQL 语言上的扩展,PL/SQL 不仅允许嵌入SQL语言,还可以定义变量和常量,可以使用条件语句、循环语句,允许使用例外处理错误。其功能十分强大,有点类似于某种后台语言(JAVA、C++、C#等)与SQL语句的结合形式。
PL/SQL是一种语言,而SQL只是一种语句。
SQL语句直接操作的几大缺陷:
1、无法进行模块化编程。只能单条的去执行,即使是事务,也是单条执行完成后一起提交而已。
2、执行速度慢。SQL语句写在编程语言中,被编程语言的编译机制编译之后,发送给DBMS,DBMS又需要重新将被编程机制编译后的SQL语句重新编译为Oracle认识的SQL语句,然后才可以执行。多次编译浪费了大量时间。
3、安全隐患。在使用SQL语句编程的同时,不可避免的需要写入需要操作的列名、表名等一部分数据。这些数据虽然表面上看似不是很重要,但对于专业人士来讲,这些数据的暴露也是很危险的。
4、浪费带宽。与执行速度的分析类似,多次的数据传输同样会浪费大量的带宽。
PL/SQL编程的优缺点:
优点:
1、提高应用程序的运行性能;
2、模块化的设计思想(分页的过程、订单的过程、转账的过程等。类似将SQL封装为函数的思想);
3、减少网络传输量;
4、提高安全性;
缺点:
1、移植性差。即不同的数据库平台之间的PL/SQL代码是不通用的。
了解了PL/SQL编程之后。我们再引入一个概念——过程。
过程及存储过程。即用来完成一个特定操作的一组SQL语句的集合。 -- 模块化编程
其整体概念有点类似于函数。当用户需要使用时,直接调用过程即可。 -- 执行速度提升
过程是经过编译之后存储在数据库中的二进制文件。 -- 安全性提升
创建存储过程(一)
基本语法:
CREATE [OR REPLACE] PROCEDURE 过程名(参数1 参数类型, 参数2 参数类型, ……)
IS --或者AS
初始化变量;
BEGIN
执行SQL语句;
END;
/
★:注意:
1、过程参数的定义方式与函数参数定义的方式不同。过程的参数定义是参数名在前,参数类型在后。
2、上述基本语法中 斜杠/ 的意义。
因为在脚本中,可能存在多条SQL语句,如果没有斜杠,则遇到分号就会执行,而在脚本定义中,不需要马上执行。
该符号多用于创建创建存储过程,其意义为:执行之前的SQL脚本。
在PL/SQL等客户端中,可以使用执行选中代码,就不必使用/。
3、IS 与 BEGIN 关键字之间的部分,仅仅用于声明变量,可以初始化,但不允许赋值;
4、传入的输入参数不允许作为赋值目标;
示例1(IS 与 BEGIN 之间可以声明变量)
SQL> CREATE OR REPLACE PROCEDURE pro_test(v_empno NUMBER)
2 IS
3 v_sal NUMBER; -- 定义变量
4 BEGIN
5 SELECT sal INTO v_sal FROM emp WHERE empno = v_empno;
6 END;
7
8 /
Procedure created
示例2(IS 与 BEGIN 之间可以声明并初始化变量)
SQL> CREATE OR REPLACE PROCEDURE pro_test(v_empno NUMBER)
2 IS
3 v_sal NUMBER := 100; -- 定义变量 并初始化
4 BEGIN
5 SELECT sal INTO v_sal FROM emp WHERE empno = v_empno;
6 END;
7 /
Procedure created
示例3(IS 与 BEGIN 之间不可以对变量进行赋值)
SQL> CREATE OR REPLACE PROCEDURE pro_test(v_empno NUMBER)
2 IS
3 v_sal NUMBER; -- 定义变量
4 v_sal := 100; -- 对变量赋值
5 BEGIN
6 SELECT sal INTO v_sal FROM emp WHERE empno = v_empno;
7 END;
8 /
Warning: Procedure created with compilation errors
SQL> show error
Errors for PROCEDURE SCOTT.PRO_TEST:
LINE/COL ERROR
-------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4/7 PLS-00103: 出现符号 "="在需要下列之一时: constant exception table long double ref char time timestamp interval date binary national character nchar 符号 "" 被替换为 "=" 后继续。
SQL>
示例4:-- 创建一个过程,其功能是删除EMP表中EMPNO为‘1234’的用户。
SELECT * FROM emp;
CREATE [OR REPLACE] PROCEDURE pro_test(eno VARCHAR2) -- CREATE OR REPLACE : 如果该过程不存在则创建,如果存在则更新替换
IS
BEGIN
DELETE FROM emp WHERE empno=eno;
END;
SELECT * FROM emp;
调用存储过程
基本语法:
以下两种语句都可以调用过程
EXEC 过程名(参数1, 参数2, ……);
CALL 过程名(参数1, 参数2, ……);
★:注意:在命令行中,可以直接使用EXEC调用存储过程。
但是在 PL/SQL 客户端中。SQL WINDOWS 窗口是无法直接执行EXEC命令的(会报错:无效的SQL命令)
需要在COMMAND WINDOW窗口下执行。
SELECT * FROM EMP;
▲ :说明:在COMMAND 窗口编写过程时,如果遇到报错,默认是不会显示错误内容的。
可以使用 SHOW ERROR 命令来查询具体报错内容。
创建存储过程(二)
建立存储过程时,还可以直接明确指定输入参数(IN)或者输出参数(OUT)。
输入参数可以将数据传递到执行部分。
输出参数可以将数据传递到应用的环境。
基本语法:
CREATE [OR REPLACE] PROCEDURE 过程名(变量 IN 变量类型……, 变量 OUT 变量类型) IS
BEGIN
执行语句;
END;
/
★ 注意:在不明确指定 IN 或 OUT 时,默认的是输入参数,即 IN 。
JAVA中调用存储过程
我们先创建一个存储过程 PRO_TEST 用来向 EMP 表中插入一条记录。
SQL> create or replace procedure pro_test(v_empno IN number, v_name IN varchar2, v_sal number) IS
2 begin
3 insert into emp(empno, ename, sal) values(v_empno, v_name, v_sal);
4 end;
5 /
Procedure created
SQL> commit; -- 一定要记得提交,否则事务目前被 COMMAND 窗口占用, java 代码是无法执行的
Commit complete
编写JAVA程序调用该存储过程。
public class TestProcedure {
public static void main(String[] args) {
Connection ct = null;
CallableStatement cs = null;
try {
// 加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//得到连接
ct = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:ORCL", "scott", "scott");
/* sql 语句 固定写法 :
* 大括号{}包含
*
* {call 过程名(占位符, 占位符, ……)}
*
* ?为占位符,需要传几个参数就写几个问号 ★ 这里的参数指 IN 参数。 OUT 参数 一会儿另行演示
* */
String sql = "{call pro_test(?,?,?)}";
// 创建 CallableStatement 接口引用对象
cs = ct.prepareCall(sql);
//对占位符 ? 赋值 注意:?的个数是从 1 开始计数
cs.setInt(1, 7777); // 第一个?赋值 7777
cs.setString(2, "jack"); // 第二个?赋值jack
cs.setFloat(3, 4000.89F); // 第三个?赋值Float类型的 4000.89
//执行 execute 方法用来执行任何种类的 SQL 语句 ,返回一个 boolean 类型
cs.execute();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
} finally {
//关闭资源 (本例省略)
}
}
}
1、单行注释: -- 内容
2、多行注释: /* 内容 */
3、变量: v_ 作为前缀。如 v_name
4、常量: c_ 作为前缀。如 c_class
5、游标: _cursor 作为后缀。 如 student_cursor
6、例外: e_ 作为前缀。 如 e_error
块是PL/SQL的基本程序单元。编写PL/SQL程序实际上就是编写PL/SQL块。
可以在一个PL/SQL块中嵌套其他的PL/SQL块来实现一些复杂的功能。
块的意义类似于其他编程语言中的类(class)。但是写法有很大的不同。
首先,块中的定义与执行是完全分开的,这与其他编程语言的类中可以随时定义变量的写法完全不同。
块 由三部分构成:定义部分、执行部分、例外部分。其结构非常严格。
块的基本结构如下:
/*定义部分(可选) -- 定义常量、变量、游标、其他数据类型等*/
DECLARE
/*执行部分(必须) -- 要执行的SQL语句或PL/SQL语句*/
BEGIN
/*例外部分(可选) -- 处理运行时可能产生的各种错误*/
EXCEPTION
END; -- 结束标志
Oracle中, 也提供了很多的常用开发包(基本上都是以 dbms_ 为前缀)。其中包含了一些过程。
示例1:
-- 在PL/SQL客户端的Command Window下打印输出 Hello World
SQL> /
SQL> set serveroutput on; -- ★ 默认打印台是关闭的,我们需要先设置打开。后面的实例省略该步骤
SQL> /
SQL> begin
2 dbms_output.put_line('Hello World!');
3 end;
4 /
Hello World!
PL/SQL procedure successfully completed
示例2:
-- 查询emp表中编号为7900的员工姓名,并将姓名赋值给一个变量。
块的写法如下:
SQL> declare -- 声明变量的关键字
2 v_name varchar2(20); -- 变量名 变量类型 ★ 这里不仅需要指定类型,还需要指定长度。
3 begin -- 执行体开始
4 select ename into v_name from emp where empno = &empno;
-- 此处 &empno 的写法 会弹出窗口要求用户输入 empno 的值
-- 从 emp 表中 查询 enamel 字段 赋值给 v_name 变量 。查询条件为 empno = 弹出对话框后用户输入的值
5 dbms_output.put_line('The name is '||v_name);
-- 输出 The name is 变量v_name的值
6 end; -- 执行体结束
7 / -- 执行上面脚本
The name is JAMES
PL/SQL procedure successfully completed
过程的写法如下:
SQL> create procedure pro_test(in_empno number)
2 IS
3 v_name varchar2(20);
4 BEGIN
5 select ename into v_name from emp where empno = in_empno;
6 dbms_output.put_line('The name is '||v_name);
7 end;
8 /
Procedure created
SQL> exec pro_test(7900);
The name is JAMES
PL/SQL procedure successfully completed
★ 注意:
在定义块时,变量不仅仅需要指定类型,还需要指定长度;
在定义过程时,参数只需要指定类型,不需要指定长度;
示例3:
-- 查询emp表中编号为1234的员工姓名,实际上该员工并不存在,我们需要让他执行异常处理。
SQL> declare
2 v_name varchar2(20);
3 begin
4 select ename into v_name from emp where empno = &empno;
5 end;
6 /
declare
v_name varchar2(20);
begin
select ename into v_name from emp where empno = 1234;
end;
ORA-01403: 未找到任何数据
ORA-06512: 在 line 4
可以看出,Oracle中默认的有提供一些异常处理机制,在没有找到数据时会有“ORA-01403:未找到数据”提示。
但是,这对于普通的用户来说,并不是所有的Oracle提示都能看的懂,所以,我们需要尝试着让Oracle在发生异常时,执行我们自己定义的语句。
异常部分的基本语法:
EXCEPTION
WHEN 异常名称 THEN
执行代码;
WHEN 异常名称2 THEN
执行代码2;
SQL> declare
2 v_name varchar2(20);
3 begin
4 select ename into v_name from emp where empno = &empno;
5 dbms_output.put_line('员工姓名:'||v_name);
6 exception
7 when no_data_found then
8 dbms_output.put_line('没有找到数据,您输入的员工号可能有误');
9 end;
10 /
没有找到数据,您输入的员工号可能有误
PL/SQL procedure successfully completed
示例中异常的处理代码仅仅是打印了自定义的一句话。
当然也可以写其他的执行语句,比如:如果没有找到该员工,就新增一条信息?
同样是可以的。只需要在第8行后加入 INSERT INTO 的SQL语句即可。