JavaEE学习日志(一百零一): Oracle高级,JDBC访问存储过程和存储函数

视图

一、什么是视图

  • 能看到的,可视化,是一个虚表
  • 视图是一张虚表,封装了一个复杂的sql查询语句
  • 可以对视图进行增删改查,视图不能存储记录,所有的数据都在基本表中(table)
  • 操作视图就是操作基本表
  • 视图一般只能用来做查询

二、视图的语法:如果权限不足,可以切换system用户来提高当前用户的权限

create [or replace] view 视图名 as sql查询语句;

sql语句的语法中:[]代表可有可无

三、举例

select * from emp_view;
select * from emp;
insert into emp_view(empno,ename) values(2001,'LiSi')

数据增加之后,在原来的表中也添加了数据。
所以,操作视图,就是操作基本表

四、作用

  1. 屏蔽敏感数据
create or replace view employee as select empno,ename,job,mgr,hiredate,deptno from emp;

注意:CRUD操作只能针对于你视图中存在的列

  1. 创建一个只读的视图
create or replace view employee as select empno,ename,job,mgr,hiredate,deptno from emp with read only;
  1. 封装了一个复杂的sql语句

索引

一、什么是索引
目录就是索引
索引创建的三大前提

  1. 百万条记录以上
  2. 经常查询使用的列
  3. 不经常修改的列
    原因:修改列会导致索引重建

注意:主键列和唯一列都是索引列,不能添加索引

二、索引的作用
提高查询的效率

三、索引的语法

对这张表的哪些列来创建索引

create index 索引的名称 on(,...);

四、测试单列索引的效率

  1. 创建表
create table a(
       id number primary key,
       text varchar2(200)
)
  1. 添加百万条数据
-- 创建序列
create sequence aseq;
-- 获取uuid
--select sys_guid() from dual;

declare

begin
  for i in 1..1000000 loop
insert into a values(aseq.nextval,sys_guid());
  end loop;
end;
  1. 添加索引前查询,约0.3s
-- 添加索引前查询
select * from a where text = 'A7CCD10B185546BBB52D66D45622B431'
  1. 添加索引
--创建索引
create index a_index on a(text)
  1. 添加索引后查询,约0.03s
select * from a where text = 'A7CCD10B185546BBB52D66D45622B431'

五、复合索引

如果,给两列以上来创建索引:
表名(name,address)

可以触发索引

select * fromwhere name=' ' and address = ''

不能触发索引:or会触发全表扫描

select * fromwhere name=' ' or address = ''

可以触发索引

select * fromwhere name=' '

不能触发索引:创建索引时后边的列名

select * fromwhere address = ''

plsql的基本语句(过程化语言)

基本语句

在sql语句的基础上,新增了if、循环等操作

plsql的基本结构

  • declare --声明
    声明变量的内容
  • begin --开始
    过程化语言,sql
  • [exception] --异常
    捕获异常
  • end --结束
--声明变量
declare
 -- 声明变量
 -- 声明普通的变量
 i number;
 -- 声明变量且赋值
 j number default 200;
 -- 声明变量,可以指定为引用类型
 -- pname的类型就是emp表中ename列的类型
 pname emp.ename%type;
 pjob emp.job%type;
 -- 声明记录类型变量:可以记录一行的类型
 e_row emp%rowtype;
begin
 -- 赋初始值
 i:=100;
 -- 打印语句
 dbms_output.put_line(i);
 -- ||oracle中的连接符
 -- ''表示一个字符串,""创建别名时可以使用
 dbms_output.put_line('j='||j); 
 -- 将查询出来的姓名打印到控制台上
 -- select .. into .. :select 查询某些列into赋值给某些变量 
 select ename into pname from emp where empno=7788;
 dbms_output.put_line(pname); 
 -- 查询两列
 select ename,job into pname,pjob from emp where empno=7788;
 dbms_output.put_line(pname); 
 dbms_output.put_line(pjob); 
 -- 查询该表的所有列
 select * into e_row from emp where empno=7788;
 dbms_output.put_line(e_row.empno||e_row.ename||e_row.job); 

 
end;

结果

100
j=200
SCOTT
SCOTT
ANALYST
7788SCOTTANALYST

if语句

语法一:

if 条件 then
	sql语句;
end if;

语法二:

if 条件 then
	sql语句;
else
	sql语句;
end if;

语法三:

if 条件 then
	sql语句;
elsif 条件 then
	sql语句;
elsif 条件 then
	sql语句;
...
else
	sql语句;
end if;
declare
   i number;
begin
   i:=&请输入;
   if i >0 then
     dbms_output.put_line('正数'); 
   elsif i<0 then
     dbms_output.put_line('负数');
   else
     dbms_output.put_line('0');
   end if;  
end;

循环语句

语法一:

for i in 集合|游标 loop
	过程化语言
end loop;

在控制台打印1-10所有的整数

declare
begin
  for i in 1..10 loop
    dbms_output.put_line(i); 
  end loop;
  
end;

语法二:

loop
	循环体;
	结束条件: exit when 条件;
end loop

在控制台打印1-10所有的整数

declare
  i number default 1;
begin
  loop
    dbms_output.put_line(i); 
    exit when i = 10;
    i:=i+1;
    
  end loop;
end;

语法三

while 条件 loop
	循环体;
end loop

在控制台打印1-10所有的整数

declare
  i number default 1;
begin
  while i<=10 loop
    dbms_output.put_line(i); 
    i:=i+1;
  end loop;
end;

游标

本质上是一个集合,存储大量的数据
游标主要解决返回多行多列的问题

select into 只能处理一行数据的问题,要处理多行数据的问题:使用游标

声明游标

cursor 游标名 is sql查询语句;

遍历游标

  1. 打开游标
open 游标名
  1. 提取一行的数据
fetch 游标名 into 变量;
-- 把游标中一行的内容读入到变量中
  1. 循环,遍历所有数据,退出
 exit  when  游标名%notfound;
 -- 没有提取到记录,就退出
  1. 关闭游标
close 游标名

在控制台上打印20号部门的所有员工信息

declare
   -- 声明游标
   cursor cur is 
              select * from emp where deptno = 20;
   
   e_row emp%rowtype;
begin
   -- 遍历游标
   open cur;
   loop -- 开始循环
   fetch cur into e_row;
   exit when cur%notfound; --没有就退出
   dbms_output.put_line('编号:'||e_row.empno||'姓名'||e_row.ename); 
   end loop; --结束循环
   close cur;
   
end;

对20号部门所有的员工涨工资

declare
   cursor cur is 
              select empno from emp where deptno = 20;
begin
   -- 涨工资
   -- 注意,for循环会自动打开和关闭游标
   -- 注意:i表示的是一行
   for i in cur loop
     -- dbms_output.put_line(i.empno); 
     update emp set sal = sal + 1 where empno = i.empno;
   end loop;  

end;

一般会结合存储过程使用

存储过程

存储过程:把过程存储起来,里面封装了一组sql语句,且提前编译好,存储在服务端。
优点:安全,效率高
一般由项目经理和dba编写存储过程
使用场景:买了一件商品,数据库的变化过程就可以存储到存储过程中

存储过程的语法
参数分类:

  • 输入型参数
  • 输出型参数
create or replace procedure 过程名(参数列表:参数1 in|out 数据类型,参数2 in|out 数据类型...) 
is|as --相当于plsql基本结构中的declare

begin

end; 

示例一:给某员工涨工资

-- 需要的参数
-- 员工编号(输入型,number),涨多少(输入型,number)
create or replace procedure updateSal(eno in number,psal in number) 
is --相当于plsql基本结构中的declare
      oldSal emp.sal%type;
      newSal emp.sal%type;
begin
      -- 查询工资:涨前
      select sal into oldSal from emp  where empno = eno
      dbms_output.put_line('涨前'||oldSal); 
      update emp set sal = sal + psal where empno = eno;
      -- 查询工资:涨后
      select sal into newSal from emp  where empno = eno;
      dbms_output.put_line('涨后'||newSal); 
end; 

-- 访问存储过程:只有输入型参数
call updateSal(7788,200);

示例二:获取某员工的年薪
存储过程

-- 获取某员工的年薪
-- 需要的参数:员工编号(输入项,number)
-- 返回:年薪(输出型,number)
create or replace procedure getYearSal(eno in number,yearSal out number) 
is --相当于plsql基本结构中的declare
   
begin
   select sal*12 + nvl(comm,0) into yearSal from emp where empno = eno;
end; 

访问存储过程:有输入有输出

--访问存储过程:访问有输入有输出的存储过程
declare
   --输出型的变量,需要声明一个变量来接收参数的值
   yearSal number;
begin
   getYearSal(7788,yearSal);
   -- 打印年薪
   dbms_output.put_line(yearSal); 
end;

示例三:查询某部门所有的员工信息

输出参数为游标类型,游标类型

  • 静态的游标类型(cursor):在声明游标时指定sql语句
  • 动态的游标类型(sys_refcursor):在使用时指定sql语句
create or replace procedure getEmps(dno in number,emps out sys_refcursor)
as
       
begin
  -- 给动态游标指定sql语句
  open emps for select * from emp where deptno = dno; 
  -- 查询了某部门的员工信息  select * from emp where deptno = dno;   
end;

注意不能使用for循环

-- 访问存储过程:有输入有输出
declare 
 emps sys_refcursor;
 --声明变量,接收游标的行内容
 e_row emp%rowtype;
begin
   getEmps(30,emps); 
   -- 遍历游标
   loop
     fetch emps into e_row;
     -- 退出
     exit when emps%notfound;
     dbms_output.put_line(e_row.empno||e_row.ename); 
   end loop;
end;

存储函数

和存储过程的定义相同

注意:

  • 存储过程和存储函数属于同一类对象,名称不能重复,且不可替换
  • 存储函数一般没有输出参数

存储函数和存储过程的区别

  1. 存储函数必须有一个返回值
  2. 可以在select语句中访问

存储函数的语法

create or replace function 函数名(参数列表:参数1 in|out 数据类型,参数2 in|out 数据类型,...)
return 数据类型
is|as

begin
	return;
end;

获取某员工的年薪

-- 参数:员工编号 in number,年薪 out number(返回值)
create or replace function getYearSalFun(eno in number) return number
is
  yearsal number;
begin
  select sal*12 +nvl(comm,0) into yearsal from emp where empno=eno;
  return yearsal;
end;


-- 访问存储函数
declare
   yearsal number;
begin
  yearsal:= getYearSalFun(7788);
  dbms_output.put_line(yearsal); 
end;

触发器

触发器:简单来说,就是监听器
作用:监听表中的数据是否发生了改变(增删改)

语法:

create or replace trigger --触发器名称
before|after --在改变数据之前(或之后)执行触发器
insert|update|delete --监听的动作
on--监听哪张表
触发器的级别
declare
begin
end

添加一条记录,在控制台打印:打印一条语句

-- 添加一条记录,在控制台打印:打印一条语句
create or replace trigger insertPrint
after
insert
on emp
declare

begin
   dbms_output.put_line('添加了一条记录'); 
end;

insert into emp(empno,ename) values(2002,'wangwu');

不能给员工降薪

create or replace trigger notUpdateLowerSal
before
update
on emp
       --触发器级别
       --表级触发器:默认
          -- 更新多条记录执行一次
       --行级触发器:for each row
          -- 更新一条记录执行一次
       --注意:使用了old,new关键字,必须使用行级触发器
for each row
declare

begin
  -- 判断涨前大于涨后
  -- 相反,不管
  -- 得到之前的工资:old.sal
  -- 得到之后的工资:new.sal
  if:old.sal>:new.sal then 
     dbms_output.put_line('不能降薪'); 
     -- 弹出提示窗口
     -- raise_application_error(p1,p2);
     --p1:错误编号 -20001到-20999
     --p2:错误信息
     raise_application_error(-20001,'不能降薪!!');
  end if;
end;
update emp set sal=sal-1 where empno=7788

jdbc

ojdbc测试

一、引入依赖:可以搜missing ojdbc来解决jar包问题

<!--该jar包是oracle的驱动jar包-->
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc14</artifactId>
            <version>10.2.0.2.0</version>
        </dependency>

二、测试

public class TestJDBC {
    String driver = "oracle.jdbc.driver.OracleDriver";
    String url = "jdbc:oracle:thin:@192.168.137.128:1521:orcl";
    String username = "scott";
    String password = "tiger";

    Connection conn;
    PreparedStatement pst;
    ResultSet rs;
    @Before
    public void init(){
        //注册驱动
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        //获取连接
        try {
            conn = DriverManager.getConnection(url,username,password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /*
        查询员工表
     */
    @Test
    public void test() throws SQLException {
        //sql语句
        String sql = "select * from emp";
        //创建预编译对象
        pst = conn.prepareStatement(sql);
        //设置参数

        //执行sql语句
        rs = pst.executeQuery();
        //处理结果集
        while (rs.next()){
            System.out.println(rs.getInt("empno")+rs.getString("ename"));
        }
    }
    @After
    public void close(){
        //关闭资源
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        //关闭资源
        if(pst!=null){
            try {
                pst.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        //关闭资源
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

jdbc执行SQL存储过程和存储函数

在这里插入图片描述
一、执行存储过程的sql语句写法

{call <procedure-name>[(<arg1>,<arg2>, ...)]} 

使用get(输出参数的索引)函数来获取结果

第一种:输出类型为int类型

@Test
    public void test2() throws SQLException {
        //sql语句
        String sql = "{call getYearSal(?,?)} ";
        //创建预编译对象
        cst = conn.prepareCall(sql);
        //设置参数
        //输入型参数
        cst.setInt(1,7788);
        //输出型参数:zh
        cst.registerOutParameter(2, OracleTypes.NUMBER);
        //执行sql语句
        cst.execute();
        //处理结果集
        int ys = cst.getInt(2);
        System.out.println(ys);
    }

第二种:输出类型为游标类型
使用getObject接收游标,并转换为结果集

@Test
    public void test3() throws SQLException {
        //sql语句
        String sql = "{call getEmps(?,?)} ";
        //创建预编译对象
        cst = conn.prepareCall(sql);
        //设置参数
        //输入型参数
        cst.setInt(1,20);
        //输出型参数:zh
        cst.registerOutParameter(2, OracleTypes.CURSOR);
        //执行sql语句
        cst.execute();
        //处理结果集
        Object object = cst.getObject(2);
        rs = (ResultSet) object;
        while (rs.next()){
            System.out.println(rs.getInt("empno")+rs.getString("ename"));
        }
    }

二、执行存储函数的sql语句写法

{?= call <procedure-name>[(<arg1>,<arg2>, ...)]}

和存储过程没什么区别

@Test
    public void test4() throws SQLException {
        //sql语句
        String sql = "{?= call getYearSalFun(?)}";
        //创建预编译对象
        cst = conn.prepareCall(sql);
        //设置参数
        //输入型参数
        cst.setInt(2,7788);
        //输出型参数:zh
        cst.registerOutParameter(1, OracleTypes.NUMBER);
        //执行sql语句
        cst.execute();
        //处理结果集
        int ys = cst.getInt(1);
        System.out.println(ys);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值