oracle存储过程
1.从HelloWolrd开始
创建存储过程
1.1第一种方式,直接创建
-- 存储过程的Hello world
create or replace procedure p_hello is
--无参的存储过程。
--声明变量
--调用方法1.新建一个TEST WINDOW begin与end之间输入 p_hello;即可执行
--在控制台里输入 exec 存储过程名
begin
dbms_output.put_line('hello world');
end p_hello;
- 测试存储过程的两种方式
- 第一种方式begin…end
-- 测试 (第一种方式)
begin
-- Call the procedure
p_hello;
end;
- 第二种方式 call procedure_name();
-- 测试 (第二种方式)
call p_hello();
commit;
- 第三种(和第一种类似)
DECLARE
begin
-- Call the procedure
p_hello;
end;
- 第四种方式(必须使用命令行的方式)
exec p_hello;
- 控制台输出
hello world
说明:
plsql的dbms_output.put_line(‘hello world’);
相当于java的System.out.println(“hello world”);
1.2第二种方式,使用package的方式
- 创建一张demo表
create table USER_INFO
(
id VARCHAR2(4),
username VARCHAR2(15),
password VARCHAR2(15),
address VARCHAR2(30)
);
- 然后定义存储过程USER_INSERT,先定义PACKAGE包头USER_CONTROL
-- 存储过程包头USER_CONTROL
CREATE OR REPLACE PACKAGE USER_CONTROL AS
PROCEDURE USER_INSERT (
in_id user_info.id%TYPE,
in_username user_info.username%TYPE,
in_password user_info.password%TYPE,
in_address user_info.address%TYPE
);
END USER_CONTROL;
- 在定义PACKAGE BODY包体USER_CONTROL,这里包头和包体的名字要相同
-- 存储过程包体
CREATE OR REPLACE PACKAGE BODY USER_CONTROL AS
PROCEDURE USER_INSERT (
in_id user_info.id%TYPE,
in_username user_info.username%TYPE,
in_password user_info.password%TYPE,
in_address user_info.address%TYPE
)IS
BEGIN
INSERT INTO USER_INFO(ID,USERNAME,PASSWORD,ADDRESS) VALUES(in_id,in_username,in_password,in_address);
END;
END USER_CONTROL;
- 调用存储过程
DECLARE
BEGIN
USER_CONTROL.USER_INSERT('11','11','11','11');
END;
说明:
1.调用存储过程测试,别忘了提交事务,否则也会不生效
2.其实我们可以简单的这样理解,把PACKAGE包头理解为JAVA中的接口,把PACKAGE BODY理解为JAVA中实现这个接口的类,而里面的存储过程就相当于类中的方法了。
2.plsql语法简单学习(面向过程编程语言)
2.1通用模板
– 语法
DECLARE
– 声明部分(变量的声明、游标的声明(cursor)、例外的声明(异常))
BEGIN
– 语句序列(DML语句)
EXCEPTION
– 例外处理语句
END;
- plsql语言的Helloworld
declare
begin
dbms_output.put_line('helloworld');
end;
2.2说明变量
DECLARE
-- 说明变量:char、varchar2、date、number、boolean、long
v_num number;
-- 赋值
v_char varchar2(24) := 'it is good';
BEGIN
-- 赋值
v_num := 10;
-- 拼接结果
dbms_output.put_line('hello, world' || '! v_num=' || v_num || ', v_char=' || v_char);
END;
控制台打印:
hello, world! v_num=10, v_char=it is good
2.3引用变量
declare
v_name demo.name%type;
begin
select name into v_name from demo where id=1;
dbms_output.put_line('v_name的值为:'||v_name);
end;
控制台打印:
v_name的值为:demo的name1
2.4记录型变量
DECLARE
-- 记录型变量
v_row demo%rowtype;
BEGIN
SELECT * INTO v_row FROM demo WHERE id = 1;
dbms_output.put_line('名字为:' || v_row.name);
END;
2.5if语法
语法
语法:
[1] IF 条件 THEN
code....;
END IF;
[2] IF 条件 THEN
code....;
ELSE
code....;
END IF;
[3] IF 条件 THEN
code....;
ELSIF 条件 THEN
code...
ELSE
code....;
END IF;
demo示例:
DECLARE
v_date VARCHAR2(24);
BEGIN
SELECT trim(to_char(SYSDATE, 'dy')) INTO v_date FROM dual; -- 当天属于周几
IF v_date IN ('sun', 'sat') THEN
dbms_output.put_line('在中国今天是周末哦!');
ELSE
dbms_output.put_line('在中国今天是工作日哦!');
END IF;
END;
2.6循环(主要掌握loop)
语法
语法:
[1] WHILE 条件
LOOP
code...;
END LOOP;
[2] LOOP
EXIT WHEN 条件
code....
END LOOP;
[3] FOR i IN 1...n
LOOP
code...
END LOOP;
demo示例1:
-- 输出1-10
-- 法一:
DECLARE
v_tag NUMBER := 1;
BEGIN
WHILE v_tag < 10
LOOP
dbms_output.put_line(v_tag);
v_tag := v_tag + 1;
END LOOP;
END;
-- 法二:
DECLARE
v_tag NUMBER := 1;
BEGIN
LOOP
EXIT WHEN v_tag >= 10;
dbms_output.put_line(v_tag);
v_tag := v_tag + 1;
END LOOP;
END;
-- 法三:
DECLARE
BEGIN
FOR i IN 1..10
LOOP
dbms_output.put_line(i);
END LOOP;
END;
demo示例2:
要求:随机向demo表中添加一百条测试数据
declare
v_int number(3,0) :=1;
begin
while
v_int<=100
loop
insert into demo select v_int,'demo的name'||v_int from dual;
commit;
v_int :=v_int+1;
dbms_output.put_line('helloworld'||v_int);
end loop;
end;
2.7游标
概念
在Java中有集合的概念,那么在plsql中也会有用到多条记录的情况,这时候我们就要用到游标。游标可以存储查询返回的多条数据。
- 语法:
-- 语法:
CURSOR 游标名 [(paramName paramType, ....)] IS SELECT 语句...;
- 取值步骤
- 打开游标 open cursor
- 开启循环 loop;
- 取值 fetch 游标名称 into 变量名
- 结束循环 end loop;
- 关闭游标 close 游标名称
- 示例
- 示例一(普通游标)
-- 使用游标方式输出员工编号和姓名
DECLARE
pemp emp%ROWTYPE;
-- 定义游标
CURSOR pc IS SELECT * FROM emp;
BEGIN
-- 打开游标
OPEN pc;
-- 取数据
LOOP
FETCH pc INTO pemp;
EXIT WHEN pc%NOTFOUND;
dbms_output.put_line(pemp.empno || '-' || pemp.ename);
END LOOP;
END;
- 示例二(系统引用游标)推荐
DECLARE
mycursor1 SYS_REFCURSOR;
vrow demo%ROWTYPE;
BEGIN
OPEN mycursor1 FOR SELECT * FROM demo;
LOOP
FETCH mycursor1 into vrow;
EXIT WHEN mycursor1%NOTFOUND;--%notfound,游标中已经取到最后,没有数据了
dbms_output.put_line(' 员工姓名:' || vrow.name || ' demoid:' || vrow.id);
END LOOP;
CLOSE mycursor1;
END;
3.plsql函数
语法:
CREATE [OR REPLACE] FUNCTION
[(param1,param2)]
RETURN IS|AS
[local declarations]
BEGIN
excutable statements;
RETURN result;
EXCEPTION
exception handlers;
END;
入门demo
要求:求两个数的和
- 新建一个函数
create or replace function add_func(a number, b number)
return number
is
begin
return (a + b);
end;
- 写测试
begin
dbms_output.put_line(add_func(1,2));
end;
-- 控制台输出3
- 在sql语句中使用plsql函数
select add_func(1,1) from dual;
-- 结果:2
4.测试oracle存储过程的crud
(1)insert
- 建表
create table STUDENT
(
sid NUMBER,
sname VARCHAR2(20),
sage NUMBER,
sgender VARCHAR2(20)
)
- 创建存储过程
- 第一种方式(可以使用,方便)
create or replace procedure pro_addstudent
(sid in student.sid%type,sname in student.sname%type , sage in student.sage%type,sgender in student.sgender%type)
is
begin
insert into student (sid,sname,sage,sgender)values(sid,sname,sage,sgender);
end;
- 第二种方式(标准的方式)
create or replace procedure pro_addstudent2
(sid in number,sname in varchar2, sage in number,sgender in varchar2)
is
begin
insert into student (sid,sname,sage,sgender)values(sid,sname,sage,sgender);
end;
问题:
存储过程中是否要对增删改的业务进行提交事务?
答:是要提交事务的,否者数据添加不进去
说明:
第一种方式使用参数类型引用的是字段的数据类型
第二种方式是自己声明参数的类型
- 测试存储过程
-- 测试 (第一种方式)
call pro_addstudent(1,'汉汉',23,'男');
Commit;
-- 测试 (第二种方式)
begin
pro_addstudent(2,'小李1',23,'女');
end;
- dao层的方法
void insertDemoByCunFun(Map<String, Object> map);
- mapper.xml里面调用存储过程
<!-- void insertDemoByCunFun(Map<String,Object> map); -->
<select id="insertDemoByCunFun" parameterType="java.util.Map">
<![CDATA[
{call pro_addstudent2(
#{sid,mode=IN,jdbcType=DOUBLE},
#{sname,mode=IN,jdbcType=VARCHAR},
#{sage,mode=IN,jdbcType=DOUBLE},
#{sgender,mode=IN,jdbcType=VARCHAR}
)}
]]>
</select>
说明:
书写要规范,否则存储过程调用会失败
<![CDATA[ ]]> 标签的使用可以解决存储过程不识别的问题
- 测试方法
@Test
public void testcun2(){
/*
* #{sid,mode=IN,jdbcType=INTEGER},
#{sname,mode=IN,jdbcType=VARCHAR},
#{sage,mode=IN,jdbcType=INTEGER},
#{sgender,mode=IN,jdbcType=VARCHAR},
sid,sname,sage,sgender
*/
Map<String, Object> mp = new HashMap<String, Object>();
mp.put("sid", 1.0);
mp.put("sname", "1111");
mp.put("sage", 2.0);
mp.put("sgender", "男");
demoDao.insertDemoByCunFun(mp);
}
- 控制台打印
无
- 进行验证
select * from student;
-- 1 1 1111 2 男
(2)select返回list集合
- (1创建测试表
create table demo(id number(5,0),name varchar2(50));
- (2使用plsql的存储过程或者不使用存储过程新建测试数据
- 第一种方式:使用declare直接创建一百条测试数据
declare
v_id number(5,0) := 1;
begin
while v_id<101
loop
insert into demo (id,name) values(v_id,'测试的demo数据'||v_id);
commit;
v_id :=v_id+1;
dbms_output.put_line('demo的id为: '||v_id||', demo的name为: '||'测试的demo数据'||v_id);
end loop;
end;
- 第二种方式:使用存储过程,直接调用存储过程
- 创建存储过程
create or replace procedure insert_sometestdata is
begin
for i in 1 ..100 loop
insert into demo(id,name) values(i, '测试的demo数据'||i);
commit;
end loop;
end insert_sometestdata;
- 调用存储过程插入数据
call insert_sometestdata();
- mybatis调用存储过程创建创建测试数据
- dao层的方法
//使用存储过程创建一百条测试数据
void insertOneHundredDataByCun();
- mapper.xml
<!-- //使用存储过程创建一百条测试数据
void insertOneHundredDataByCun(); -->
<select id="insertOneHundredDataByCun" statementType="CALLABLE">
<![CDATA[
{call insert_sometestdata(
)}
]]>
</select>
- 测试方法进行添加
/**
* mybatis调用存储过程插入一百条数据
*/
@Test
public void testinsertOneHundredDataByCun() {
demoDao.insertOneHundredDataByCun();
}
- (3 创建存储过程
create or replace procedure demo_List (v_id in number,v_cursor out sys_refcursor) is
begin
open v_cursor for select * from demo where id < v_id;
end ;
- (4 dao层方法
//并接收返回值(游标类型)
List<Map<String,Object>> queryByCuncursor(Map<String,Object> map);
- (5 mapper.xml
<resultMap type="com.fcmap.ssm.domain.Demo" id="demo_rp">
<result column="id" property="id" />
<result column="name" property="name" />
</resultMap>
<!-- List<Map<String,Object>> queryByCuncursor(Map<String,Object> map); -->
<select id="queryByCuncursor" parameterType="java.util.HashMap"
statementType="CALLABLE">
<![CDATA[
{call demo_List(
#{v_id,mode=IN,jdbcType=INTEGER},#{result,mode=OUT,
jdbcType=CURSOR,javaType=ResultSet,resultMap=demo_rp}
)}
]]>
</select>
- (6 测试方法查询结果集
@Test
public void testCunreturnCursor() {
Map<String, Object> map = new HashMap<String,Object>();
map.put("v_id",10);
map.put("result", OracleTypes.CURSOR);
demoDao.queryByCuncursor(map);
List<Demo> demoList= (List<Demo>) map.get("result");
System.out.println(demoList);
}