Oracle使用(二)---存储过程,存储函数,触发器

存储过程:

1.语法:

create [or replace] procedure 过程名(参数列表)

as

PLSQL子程序体

2.例子:

create or replace procedure queryStudent(stid in number)
as
stname STUDENT.SNAME%type;
stscore STUDENT.SCORE%type;
begin
select sname,score into stname,stscore from student where sid=stid;
dbms_output.put_line('the name is '||stname||', score is '||stscore);
end;
/

带有out参数的例子:

create or replace procedure queryStudentWithOut(stid in number,stname out varchar2,stscore out number)
as
begin
select sname,score into stname,stscore from student where sid=stid;
end;
/

调用存储过程有两种方式:

1)exec queryStudent(1);
2)在begin---end程序块中执行。

对于带有out参数的存储过程,调用例子:

DECLARE
  STID NUMBER;
  STNAME VARCHAR2(200);
  STSCORE NUMBER;
BEGIN
  STID := 1;
  QUERYSTUDENTWITHOUT(
    STID => STID,
    STNAME => STNAME,
    STSCORE => STSCORE
  );
DBMS_OUTPUT.PUT_LINE('STNAME = ' || STNAME);
DBMS_OUTPUT.PUT_LINE('STSCORE = ' || STSCORE);
END;


java中调用存储过程的例子:

	public static void main(String[] args) {
		
		String sql = "{call queryStudentWithOut(?,?,?)}";
		Connection conn = null;
		CallableStatement call = null;
		
		try {
			conn = JDBCUtils.getConnection();
			call = conn.prepareCall(sql);
			call.setInt(1, 1);
			call.registerOutParameter(2, OracleTypes.VARCHAR);
			call.registerOutParameter(3, OracleTypes.NUMBER);
			
			call.execute();
			
			String name = call.getString(2);
			double score = call.getDouble(3);
			System.out.println(name);
			System.out.println(score);
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			JDBCUtils.release(conn, call, null);
		}
		
	}


存储函数:

语法:

create [or replace] function 函数名(参数列表)

return 函数返回值类型

as

PLSQL子程序体

例子:

create or replace function queryStudentScore(stid in number)
return number
as
tscore student.score%type;
begin
select score into tscore from student where sid=stid;
return tscore*100;
end;
/

在begin--end语句块中可调用。

java中调用存储函数的例子:

	public static void main(String[] args) {
		
		String sql = "{?=call queryStudentScore(?)}";
		Connection conn = null;
		CallableStatement call = null;
		try {
			conn = JDBCUtils.getConnection();
			call = conn.prepareCall(sql);
			call.registerOutParameter(1, OracleTypes.NUMBER);
			call.setInt(2, 1);
			
			call.execute();
			
			double score = call.getDouble(1);
			System.out.println(score);
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			JDBCUtils.release(conn, call, null);
		}
		
	}

注意java调用存储过程和存储函数时sql的不同。

在out类型的参数存在的情况下,存储过程与存储函数基本没什么区别,但是在使用中应遵循只有一个返回参数使用存储函数,有多个返回参数使用存储过程(只是因为大家都这样使用)。

在oracle sql developer中可以进行调试存储过程与存储函数,需要的权限有debug connect session和debug any procedure, 查看某个用户具有的权限的命令为:

select * from dba_sys_privs where grantee='HURRICANE';

赋予相应权限的命令为:grant debug connect session,debug any procedure to hurricane;

调试应先“编译已进行调试”。

重点:在存储过程返回的结果集有成百上千行时,再使用普通形式的存储过程,需要相应的声明成百上千的out参数,显然是不合适的,在这种情况下,需要结合游标来获取结果集。

在out参数中使用游标:

1):创建一个包:mypackage

2)在该包中定义一个自定义类型:mycursor 类型为游标(cursor)

  一个存储过程:querystu

create or replace package mypackage as
    type mycursor is ref cursor;
    procedure querystu(stid in number,stout out mycursor);
end mypackage;
create or replace
package body mypackage as
procedure querystu(stid in number,stout out mycursor) as
begin
 open stout for select * from student where sid=stid;
end querystu;
end mypackage;


java调用的代码为:

	public static void main(String[] args) {
		String sql = "{call mypackage.querystu(?,?)}";
		Connection conn = null;
		CallableStatement call = null;
		ResultSet rs = null;
		try {
			conn = JDBCUtils.getConnection();
			call = conn.prepareCall(sql);
			call.setInt(1, 1);
			call.registerOutParameter(2, OracleTypes.CURSOR);

			call.execute();

			rs = ((OracleCallableStatement)call).getCursor(2);
			while (rs.next()) {
				System.out.println(rs.getString("sname")+"   "+rs.getDouble("score"));
			}

		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			JDBCUtils.release(conn, call, rs);
		}
	}

触发器:

数据库触发器是一个与表关联的,存储的PL/SQL程序。每当一个特定的数据操作语句(insert,update,delete)在指定的表上发出时,oracle自动地执行触发器中定义的语句序列。

触发器的类型有:

1)语句级触发器,在指定的操作语句操作之前或之后执行一次,不管这条语句影响了多少行;

 2)行级触发器,触发器语句作用的每一条记录都被触发。在行级触发器中使用old和new伪记录变量,识别值得状态。

语法:

create [or replace] trigger 触发器名

{before|after}

{delete|insert|update[ of 列名]}

on 表名

[for each row [when (条件)]]

PL/SQL块

例子:

create or replace trigger beforeInsertStudent
before insert
on student
for each row
begin
if :new.score>150 then
    raise_application_error(-20002,'分数不能大于150, 分数为'||:new.score);
end if;
end;
/


触发器应用场景:

1):数据确认

2):实施复杂的安全性检查

3):做审计,跟踪表上所做的数据操作等

4):数据的备份和同步

查询触发器,过程,函数:

select * from user_triggers;

select * from user_source;

触发器案例:

案例一:

/*
示例1:限制非工作时间向数据库插入数据

周末:to_char(sysdate,'day') in ('星期六','星期日')
<9点或者 > 18点:  to_number(to_char(sysdate,'hh24')) not between 9 and 18
*/
create or replace trigger securityEmp
before insert
on emp
begin

  if to_char(sysdate,'day') in ('星期六','星期日','星期三') or 
      to_number(to_char(sysdate,'hh24')) not between 9 and 18 then
      raise_application_error(-20001,'不能在非工作时间插入数据');
  end if;    
end;
/


案例二:

/*
确认数据:涨后的工资不能少于涨前的工资
*/
create or replace trigger checksal
before update
on emp
for each row
begin

  if :old.sal > :new.sal then
    raise_application_error(-20002,'涨后的薪水不能少于涨前的薪水。涨前:'||:old.sal||'  涨后:'||:new.sal);    
  end if;

end;
/

java链接oracle需要的jar包可在 ..\oracle\product\11.2.0\dbhome_1\jdbc\lib下找到

链接路径为:jdbc:oracle:thin:@localhost:1521:实例名

驱动类:oracle.jdbc.OracleDriver

注意JDBCUtils 中链接,结果集等的关闭方式,用try包裹,finally中将其置为空。

package demo.utils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBCUtils {
	private static String driver = "oracle.jdbc.OracleDriver";
	private static String url = "jdbc:oracle:thin:@localhost:1521:orcl";
	private static String user = "scott";
	private static String password = "tiger";
	static{
		try {
			Class.forName(driver);
		} catch (ClassNotFoundException e) {
			throw new ExceptionInInitializerError(e);
		}
	}
	
	public static Connection getConnection(){
		try {
			return DriverManager.getConnection(url, user, password);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}
	/*
	 * 执行java程序:
	 * java -Xms100M -Xmx200M HelloWorld  运行HelloWorld最小分配100M内存,
	 */
	public static void release(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; //??????
			}
		}		
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值