oracle视频学习(三)

触发器是隐含的执行存储过程。当定义触发器时候,必须指定触发的事件
和触发的动作,而触发事件包括insert,update,delete语句,而触发器实际就
是一个Pl/sql块,可以使用create tigger来建立触发器
 
 触发器是非常有用的,可以维护数据库的安全和一致性,类似监听器功能

 在编写pl/sql程序时候,可以定义变量和常量;在pl/sql程序中包括有:
 1: 标量类型 scalar
 2: 符合类型 composite
 3: 参照类型 reference
 4: lob large object

标量scalar -----使用标量
 在定义好变量后,就可以使用这些变量,这里需要说明的是pl/sql块
为变量赋值不同于其它编程语言,需要在等号前加冒号(:=)

标量的定义
 1,定义一个变长字符串
 v_ename varchar2(10);
 
  定义一个小数 
 v_sal number(6,2);
   定义一个小数并且给一个初始值5.4 :=是pl/sql的赋值号
 v_sal number(6.2):=5.4;
 定义一个日期类型的数据
 v_hiredate date;
 定义一个布尔变量 不能为空 初始值是FALSE
 v_valid boolean not null default false;

 输入员工号 显示雇员姓名 工资 个人所得税 为例子,说明变量的使用
 
declare
c_tax_rate number(3,2):=0.03;
v_ename varchar
-----用户名
v_ename varchar2(5);
v_sal number(7,2);
v_tax_sal number(7,2);
begin
----执行
select ename,sal into v_ename,v_sal from emp where empno=&no;
----计算所得税
v_tax_sal:=v_sal*v_tax_rate; (///赋值的时候一定要是:=)
----输出
dbms_output.put_line('姓名是:'||v_name||'工资:'||v_sal||'交税')
end;
/
标量scalar---使用%type类型:
v_ename varchar2(5);
对于上面的pl/sql块有一个问题:就是如果员工的姓名超过了5个字符的话,就会有错误
为了降低pl/sql程序的维护工作量,可以确定使用%type属性定义标量,这样它会按照数据库
列来确定你定义的变量的类型和长度.
怎么使用:
标识符名 表名.列名%type;
v_ename emp.ename%type; (这个类型和表emp表的ename这个字段的数据类型一摸一样)
v_sal emp.sal%type;

符合变量 composite ---介绍
用于存放多个值的变量,主要包括这几种:
pl/sql 记录
pl/sql表
嵌套表
varray
 
复合类型---pl/sql记录
类似与高级语言中的结构体,需要特别注意的是,当应用pl/sql记录成员时候,必须要加
记录变量作为前缀(记录变量.记录成员)如下:
记录类型,结构体类型;
declare
-----定义了一个pl/sql记录类型emp_record_type
type emp_record_type is record(
name emp.ename%type,
salary emp.sal%type,
title emp.job%type);
-----定义了一个变量sp_record,这个变量的类型是emp_record_type
-----存放了三个变量的结构体类型
sp_record emp_record_type;
begin
----一下子取出三个数据赋给一个记录变量
select ename,sal,job into sp_record
from emp where empno=7788;
------输出结构体变量中的一个属性值
dbms_outoput.put_line('员工名:'||sp_record.name);
end;
)
符合类型-pl/sql表
相当于高级语言中的数组,但是需要注意的是在高级语言中数组的下标不能为
负数,而pl/sql是可以为负数的,并且表元素的下标没有限制
declare
---定义了一个pl/sql表类型sp_table_type,该类型是用于存放emp.ename%type
type sp_table_type is table of emp.ename%type
---表的下标是整数
index by binary_integer;
---定义了一个变量,是sp_table_type数据类型;
sp_table sp_table_type;
begin
//如果把where条件去掉会怎样? 使用参照变量
select ename into sp_table(0) frome emp where empno=7788;
dbms_output.put_line('员工名:'||sp_table(0));
end;
说明:
sp_table_type 是pl/sql类型
emp.ename%type 指定了表的元素的类型和长度
sp_table 为pl/sql表变量
sp_table(0) 则表示下标为0的元素
 
参照变量介绍
参照变量是指用于存放数值指针的变量,通过使用参照变量,可以使得应用程序共享
相同的对象,从而降低占用的空间,在编写pl/sql程序时候,可以使用游标变量ref cursor
和对象类型变量ref obj_type两种参照变量类型;
游标就是一个指针来回的指来回的取值;
--------------------------
参照变量 --ref cursor游标变量
当使用游标的时候,当定义游标时候不需要指定相应的select语句,但是当使用游标时候(open)
需要指定select语句,这样一个游标就与一个select语句结合了:
请使用pl/sql编写一个块,可以输入部门号,并且显示该部门所有员工姓名和他的工资
在上要求基础上,如果某个员工的工资低于200元,就增加100;

declare
---定义一个游标类型sp_emp_cursor
type sp_emp_cursor is ref cursor;
---定义一个游标变量test_cursor 是sp_emp_cursor类型的
test_cursor sp_emp_cursor;
v_ename emp.ename%type;
v_sal emp.sal%type;
begin
----执行
----把test_cursor和一个select结合
----把游标指向select后的结果集
open test_cursor for select ename,sal from emp where deptno=&no;
---循环取出数据
loop 
  fetch test_cursor into v_ename,v_sal //循环一次赋予变量一次值
  ----判断是否test_cursor为空,指向的地址为空,取不出值
  exit when test_cursor%notfound;
  dbms_output.put_line('名字:'||v_ename||'工资:'||v_sal);
end loop;
---关闭游标
  close test_cursor;
end;
/

-----------------------------------
declare
---定义一个游标类型sp_emp_cursor
type sp_emp_cursor is ref cursor;
---定义一个游标变量test_cursor 是sp_emp_cursor类型的
test_cursor sp_emp_cursor;
v_ename emp.ename%type;
v_sal emp.sal%type;
begin
----执行
----把test_cursor和一个select结合
----把游标指向select后的结果集
open test_cursor for select ename,sal from emp where deptno=&no;
---循环取出数据
loop 
  fetch test_cursor into v_ename,v_sal //循环一次赋予变量一次值
  ----判断是否test_cursor为空,指向的地址为空,取不出值
  ----判断工资高低是否加工资;
  exit when test_cursor%notfound;
  dbms_output.put_line('名字:'||v_ename||'工资:'||v_sal);
end loop;
---关闭游标
  close test_cursor;
end;
/
 
 
  oracle的视图
  Oracle的视图 oracle的触发器

  讲oracle不讲视图是不可能的
  会编写oracle各种触发器

pl/sql 介绍
在任何计算机语言(c,java,pascal)都有各种控制语句
(条件语句,循环语句,顺序控制结构)在pl/sql中也存在这样的控制结构
 使用各种if语句
 使用循环语句
 使用控制语句 ---goto和null

 条件分支语句
 pl/sql提供了三种条件分支语句
if -then  
//if  -then -else 
//if --then --elseif ---else
简单的条件判断 if--then
编写一个过程,可以输入一个雇员名,如果该雇员的工资低于2000,就给该雇员工资增加10%
create or replace procedure sp_pro(spName varchar2) is//参数只写类型就可以了
---定义
v_sal emp.sal%type;
begin
---执行
select sal into v_sal from emp where ename=spName;
---判断
if v_sal<2000 then 
update emp set sal=sal+sal*10% where ename=spName;
end if; //如果没有end if 相对于上面的if后的语句没有结束,显然是错误的
end;

exec sp_pro('SCOTT');
-------------------------------------------

declare
---定义一个游标类型sp_emp_cursor
type sp_emp_cursor is ref cursor;
---定义一个游标变量test_cursor 是sp_emp_cursor类型的
test_cursor sp_emp_cursor;
v_ename emp.ename%type;
v_sal emp.sal%type;
begin
----执行
----把test_cursor和一个select结合
----把游标指向select后的结果集
open test_cursor for select ename,sal from emp where deptno=&no;
---循环取出数据
loop 
  fetch test_cursor into v_ename,v_sal //循环一次赋予变量一次值
  ----判断是否test_cursor为空,指向的地址为空,取不出值
  ----判断工资高低是否加工资;
  if v_ename<2000 then
  update emp set sal=sal+sal*10%;
  end if;
  exit when test_cursor%notfound;
  dbms_output.put_line('名字:'||v_ename||'工资:'||v_sal);
end loop;
---关闭游标
  close test_cursor;
end;
/
------------------------------
二重分支,if--then--else
编写一个过程,可以输入一个雇员名,如果该雇员的补助不是0就在原来的基础上增加
100,如果补助为0就把补助设为200;
 
create or replace procedure sp_pro(spName varchar2) is//参数只写类型就可以了
---定义
v_comm emp.comm%type;
begin
---执行
select comm into v_comm from emp where ename=spName;
---判断
if v_comm<>0 then  //pl/sql中不相等用<>表示
if v_sal<2000 then 
update emp set comm =comm+100 where ename=spName; 
else
update emp set comm=comm+200 where ename=spName;
end if; //如果没有end if 相对于上面的if后的语句没有结束,显然是错误的
end;

exec sp_pro('SCOTT');

-----------------------------------------------------------
多重条件分支if--then--elseif--else
编写一个过程,可以输入一个雇员标号,如果该雇员的职位是president就给他工资
增加1000,如果该雇员的职位是manager就给他工资增加500,其他的雇员工资增加200
create or replace procedure sp_pro(spNo number) is  //和字段的数据类型一致
---定义
v_job emp.job%type;
begin
---执行
select job into v_job from emp where empno=spo;
if v_job='PRESIDENT' then
update emp set sal=sal+1000 where empno=spNo;
elsif v_job='MANAGER' then  //看清楚是elsif而不是elseif
update emp set sal=sal+500 where empno=spNo;
else 
update emp set sal=sal+200 where empno=spNo;
end if; //当然有if一定要记得有endif;
end;
----------------------------------------------------
循环语句 --loop
 是pl/sql中最简单的循环语句,这种循环语句以loop开头,
以end loop结尾,这种循环至少会被执行一次;
 请编写一个过程,可以输入用户名,并且循环添加10个用户到
users表中
create or replace procedure sp_pro(spName varchar2) is 
--定义部分
v_num number:=1; //初始化值为1,赋值是:=表示赋值
begin
loop
  insert into users values(v_num,spName);
  --判断是否要退出循环
  exit when v_num=10;
  ---自增
  v_num:=v_num+1;
end loop;
end;
exec sp_pro('rufus'); //循环添加10条数据

create table users(userNo number(2),userName varchar2(10));
------------------------------------------------------------------
循环语句 -while循环
 基本循环(loop)至少要执行循环体一次,而对于while循环来说,只要条件true时候,
才会执行循环体语句,while循环while...loop开始,以end loop结束
 编写一个过程,可以输入用户名,并循环添加10个用户到users表中,用户编号从11开始
create or replace procedure sp_pro(spName varchar2) is
v_num number:=11;
begin
while v_num<=20 loop
insert into users values(v_num,spName);
---自增
  v_num:=v_num+1;
end loop;
end;
exec sp_pro('rufus'); //循环添加10条数据
create table users(userNo number(2),userName varchar2(10));
----------------------------------------------------------------------
循环语句 -for循环
 基本for循环的基本结构如下
 begin 
   for i in reverse 1..10 loop
   insert into users values(i,'rufus');
   end loop;
 end;
 /
----我们可以看到控制变量i,在隐含中就不停的增加
-------------------------------------------------------------
顺序控制语句 -goto,null
goto语句
 goto语句用于跳转到特定标号去执行语句,注意由于使用goto语句会增加
程序的复杂性,并且使得应用程序的可读性变差,所以少用;
基本语法如下goto lable,其中label是已经定义好的标号名
declare 
i int:=1;
begin 
 loop
 dbms_output.put_lien('输出i='||i);
 if i=10 then
 goto end_loop;
 end if;
 i:=i+1;
 end loop;
 <<end_loop>>
 dbms_output.put_line('循环结束');
 end;
 
 
  oracle将例外分为预定义例外,非预定义例外,自定义例外三种:
  1)编写一个过程,可以接受雇员的编号,并显示该雇员的姓名
    问题是,如果输入的雇员编号不存在,怎样去处理呢?
    declare
    v_ename emp.ename%type;
    begin
    select ename into v_ename from emp where empno=&no;
    dbms_output.put_line('name:'||v_ename); 
    exception
        when no_data_found then //认为很常见的异常,预定义
        dbms_output.put_line('编号没有');
    end;
 pl/sql为开发人员提供了二十多个例外;
 
 case_no_found  :多条件分支不全面
 cursor_already_open :游标已经打开异常
 dup_val_on_index :
 invalid_cursor:
 invalid_number: 输入的数据有错误
 no_date_found
 too_many_rows; 如果返回超过一行,则会触发例外;
 zero_divide; 当执行除数为0会触发例外;
 value_error:
视图:视图是一个虚拟表,其内容是由查询定义,同真实表的表是一样的
视图包括一系列带有名称的列和行数据,但是,视图并不是在数据库中以存储
的数据值集形式存在,行和列数据来自定义视图的查询所引用的表,并且在引用
视图时候动态生成;
emp dept
1) 如果要显示各个雇员的名字和他所在部门的名称,必须用两张表. emp,dept
2) 假设管理员创建了一个用户Rufus,可以查询sal<1000 有哪些雇员?
   视图就是从emp表中取出一些数据,从dept表中取出一些数据构成一张新的数据表
   使用视图可以简化 复杂查询  视图可以利于提高安全性;

 oracle视图
 crate view 视图名 as select 语句 [with read onyl]
 创建或修改视图
 create or replace view 视图名 as select 语句[ with read only]
 删除视图
 drop view 视图名
 create view myview as select from emp where sal<1000;
 select * from myview;
 

触发器的设计
1) 触发器概述,分类
2) 事务概述
3) 行级触发器工作原理
4) 行级触发器的设计应用
5) 语句级触发器的设计应用
6) 替代触发器应用
什么是事务:
事务是数据库中重要的机制,用于确保数据完整性和并发处理的能力,
它将一条/一组sql语句当做成一个逻辑上的单元,用于保障这些语句都
成功或是失败.
事务特性
事务具有acid四个特性 (酸的特性)
A atomicity原子性
c consistency一致性
I isolation 隔离性
d durability永久性
隔离性和并发处理的能力成反比
SQLPLUS " / as sysdba"
比如在Oracle中一个界面删除某张表的全部数据,用另一张表查看数据表中的数据全部都在
因为oracle中的操作不是自动提交的.
select * from scott.emp; //存在视图的概念,删除不提交,在自己的界面看到删除后的结果
只有真真提交后才完成对数据库的修改;
通过事务的隔离性来解决问题的,我参看的时候采取隔离,你就不能对数据进行更新操作;

还有三张票,你要卖两张,我也要卖两张.但是我仅仅是查看你是可以对数据表进行更新操作的
但是我做一个动作你就无法操作跟新了,等我提交后你才能进行更新操作:
select * from books for update;
此时对方是无法修改了,我没有操作完成,你是操作不了表的数据的,这就是事务隔离性;
这是采用了锁的机制的,当我在操作时候,我是可以对数据表进行更新操作的;
通过加锁就是为了解决并发操作出现些问题;
update books set book_name='aa' where booK_id ='0008';
commit;
对同样一个事务而言,一旦发生就永久了,成了具体的物理文件了,无法挽回了.
------------------------------------------------------------------------------------

  行级触发器,是针对增,删,改操作语句起作用的;
  参照完整性: 例如员工表,部门表: 很简单的每一个员工肯定对应一个部门,如果
  某个员工所对应的部门号在部门表中不存在,那么这个员工就毫无意义;
  怎样能实现这样一种的情况,部门表中的部门号变了,员工表中员工对应的部门号也相应改变,
  如果变了,不能级联改变,这数据表就没有意义了;

  //下面是一个行级触发器
  create or replace trigger del_deptid
  after delete on deptment
  for each row
  begin
  delete from emp where id=:old.id;
  end del_dept;
  /
  trigger created;
  我们来测试行级触发器
  delete from deptment where id='01';

   
  create or replace trigger del_deptid
  after delete on dept
  for each row
  begin
  delete from emp where empno=:old.empno;
  end del_deptid;
  /
--------------------------------------------------我们操作scott.emp表和scott.dept表
SQL> create or replace trigger del_deptno
  2  after delete on dept
  3  for each row
  4  begin
  5  delete from emp where deptno=:old.deptno;
  6  end;
  7  /
 
Trigger created

  
 create or replace trigger insert_dept
 after insert on department
 for each row 
 begin
 insert into emp (eid,ename,id) values('121','qwert',:new.id);
 end;
 /
---------------------------------------------------

:old.deptno;
:new.id
逻辑上的表,物理文件上的表.
(两个重要的内存表,随便理解表,视图虚表之类的)
        old    new
insert    -    yes
delete   yes    -
update   yes   yes
 
最重要的操作,对表做级联更新: (不同于插入和删除操作,这里是更新操作)
create or replace trigger update_dept
after update on deptment
for each row
begin
update emp set id=:new.id where id=:old.id;
end;
/
update deptment set id='yy' where id='10';
----------------------------------------------------
create or replace trigger books_delete
after delete on books
for each row
begin
if:old.books_id='0001' then
raise_application_error(-20000,'不能删除!'); //两个参数,一个为错误号,一个为错误消息
end if;
end;
/

application服务器的自定义实例raise_application_error
写的数值在区间:  -299999 ~ -20000

行级触发器,对于涉及到的每一行都会做检查的,因为它涉及到数据库的完整性问题
--------------------------------------------------------------------------
  下面看看语句级触发器问题:
  首先创建一个日志表:
  create talbe mylog(curr_user varchar2(100),curr_date date,act char(1));
  创建语句级的触发器:
  create or replace trigger dml_aa
  after insert or delete or update on aa
  begin
  if inserting then
  insert into mylog values(user,sysdate,'I');
  elsif deleting then
  insert into mylog values(user,sysdate,'D');
  else
  insert into mylog values(user,sysdate,'U');
  end if;
  end;

  save c:\trigger01.txt;

select myseq.nextval from dual;
insert into auto vlues(mysql.nextval,'sd');

利用触发器实现表的列的自增:
create or replace trigger set_no
before insert on auto
for each row
declare
sn number(5);
begin 
select mysql.nextval into en from dual;
:new.a:=sn;
end;
/
 
------------------------------------
 替换触发器的应用,注意替换触发器只能发生在视图上面:
 利用视图触发器可以解决多表更新的问题,功能很强大:
 
 create or replace trigger tr_v_e_d
 instead of insert on v_emp_dept
 for each row
 begin
 insert into department values(:new.id,:new.name);
 insert into emp(eid,ename,sex,id) values(:new.eid,:new.ename,:new.sex,:new.id);
 end;
 /
 
  pl/sql的进阶 --编写分页过程
   介绍:分页是任何一个网站(bbs,网上商城,blog)都会用到的

1) 无返回值的存储过程:
  eg:现有一张表book,表结构如下
 书号,书名,出版社:
 请编写一个过程,可以向book表中添加书,要求通过java程序调用该过程
 
  建表book
 create table book(bookId number,bookName varchar2(50),publishHouse varchar2(50));
 -----编写过程 
(in表示是往存储过程中输入的变量,如果不写in默认就是in)
(out表示是一个输出参数如果不写默认就是in)
 create or replace procedure sp_pro
(spBookId in number varchar2,spbookName varchar2,sppublishHouse in varchar2) is 
begin
 insert into book values(spBookId,spbookName,sppublishHouse);
end;
/
-----看看如何在Java如何调用;
///调用一个无返回值的过程
 
public class Test{
 public static void main(String[] args){
   try{
        //加载驱动
   Class.forName("oracle.jdbc.driver.OracleDriver");
   Connection ct=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORCL","scott","tiger"); //获得数据库连接
   //创建callablestatement
   CallableStatement cs =ct.prepareCall("{call sp_pro(?,?,?)}");
   cs.setInt(1,10);
   cs.setString(2,"prison break");
   cs.setString(3,"china publisher");
   //执行
   cs.execute();
   //关闭,最好在finally里面关闭
       }catch{
            e.printeStackTrace();
          }finally{
           //关闭各种打开的资源
            cs.close();
            ct.close();
         }
  }
}
-----------------------------------------------------------------------------------
  有返回值的存储过程(非列表)
 
1) 编写一个过程,可以输入雇员的编号,返回该雇员的姓名
2) 编写一个过程,可以输入雇员的编号,返回该雇员的姓名,工资,和岗位

eg: 有输入和输出的存储过程
 create or replace procedure sp_pro
(spno in number,spName out varchar2) is 
begin
select ename into spName from emp where empno=spno;//查出的值已经赋给变量spName了
end;
/

public class Test{
 public static void main(String[] args){
   try{
        //加载驱动
   Class.forName("oracle.jdbc.driver.OracleDriver");
   Connection ct=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORCL","scott","tiger"); //获得数据库连接
  //创建callablestatement
  //看看如何调用有返回值的过程
  CallableStatement cs =ct.prepareCall("{call sp_pro(?,?)}");
  //给一个?赋值
  cs.serInt(1,7788);
  //给二个?赋值
  cs.registerOutParameter(2,oracle.jdbc.OracleTypes.VARCHAR);
  //执行
  cs.execute();
  //取出返回值
  String name =cs.getString(2);
  System.out.println(name);
   //执行
   cs.execute();
   //关闭,最好在finally里面关闭
       }catch{
            e.printeStackTrace();
          }finally{
           //关闭各种打开的资源
            cs.close();
            ct.close();
         }
  }
}
-----------------------------------------------------------------------------

create or replace procedure sp_pro
(spno in number,spName out varchar2, spSal out number,spJob out varchar2) is
begin
select ename,sal,job into spName,spSal,spJob from emp where empno=spno;
end;
 
public class Test{
 public static void main(String[] args){
   try{
        //加载驱动
   Class.forName("oracle.jdbc.driver.OracleDriver");
   Connection ct=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORCL","scott","tiger"); //获得数据库连接
  //创建callablestatement
  //看看如何调用有返回值的过程
  CallableStatement cs =ct.prepareCall("{call sp_pro(?,?,?,?)}");
  //给一个?赋值
  cs.serInt(1,7788);
  //给二个?赋值
  cs.registerOutParameter(2,oracle.jdbc.OracleTypes.VARCHAR);
  cs.registerOutParameter(3,oracle.jdbc.OracleTypes.DOUBLE);
  cs.registerOutParameter(4,oracle.jdbc.OracleTypes.VARCHAR);
  //执行
  cs.execute();
  //取出返回值
  String name =cs.getString(2);
  String job=cs.getString(4);
  System.out.println(name+" "+job);
   //执行
   cs.execute();
   //关闭,最好在finally里面关闭
       }catch{
            e.printeStackTrace();
          }finally{
           //关闭各种打开的资源
            cs.close();
            ct.close();
         }
  }
}
--------------------------------------------------------------------------------
有返回值的存储过程
 案例:编写有返回值的存储过程(列表|结果集)
  由于oracle存储过程没有返回值,它的返回值都是通过out参数来替代的,列表
同样也不例外,但由于是集合,所以不鞥用一般的参数,必须要用package了,所以
要分两个部分;

1) 建立一个包,在该包中定义了一个游标类型,这里定义的游标类型是test_cursor
create or replace package testpackage AS
TYPE test_cursor is ref cursor;
end testpackage;
2) 创建过程
create or replace procedure sp_pro
(spNo in number,p_cursor out testpackage.test_cursor)
begin
open p_cursor for select * from emp where deptno=spNo;
end;
3)如何在java中调用
public class Test{
 public static void main(String[] args){
   try{
        //加载驱动
   Class.forName("oracle.jdbc.driver.OracleDriver");
   Connection ct=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORCL","scott","tiger"); //获得数据库连接
   //创建callablestatement
   CallableStatement cs =ct.prepareCall("{call sp_pro(?,?)}");
   cs.setInt(1,10);
   cs.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR); //注册的类型是cursor
   //执行
   cs.execute();
   ResultSet rs=(ResultSet)cs.getObject(2);
   while(rs.next()){
    System.out.println(rs.getInt(1)+"  "+rs.getString(2));
   }
   //关闭,最好在finally里面关闭
       }catch{
            e.printeStackTrace();
          }finally{
           //关闭各种打开的资源
            cs.close();
            ct.close();
         }
  }
}
 
 
     在Java中操作数据库
     public class TestOra{
     public static void main(String[] args){
        try{
  //加载驱动
 Class.forName("sun.jdbc.odbc.JdbcodbcDriver");
  //得到连接,桥连接
 Connection ct=DriverManger.getConnection("jdbc:odbc:testsp","scott","tiger");
 //从下面开始就和其他操作是一样的
 Statement sm=ct.createStatement();
 ResultSet rs=sm.executeQuery("select * from emp");
 while(rs.next()){
  //用户名
 System.out.println("用户名:"+rs.getString(2));
             }
          }catch(Exception e){
              e.printStackTrace();
           }
     }
   }
odbc如何配置数据源:
 控制面板---->管理工具----->数据源----->odbc数据源管理器---->驱动程序
 data source name--->testsp
 tns service name--->myora1
-----------------------------------------------------------
   通过jdbc来连接数据库:
public class testOra{
  public static void main(String[] args){
     try{
       //1,加载驱动
       Class.forName("oracle.jdbc.driver.OracleDriver");
       //2,得到连接
       Connection ct=DriverManger.getConnection("jdbc:oracle:thin:@localhost:1521:ORCL","scott","tiger");
 //从下面开始就和其他操作是一样的
 Statement sm=ct.createStatement();
 ResultSet rs=sm.executeQuery("select * from emp");
 while(rs.next()){
  //用户名
 System.out.println("用户名:"+rs.getString(2));
             }
          }catch(Exception e){
              e.printStackTrace();
           }
}
   }
--------------------------------------------------------
  写一个oracle分页实例:
<%@ page language="java" import="java.util.*,com.sql.*" pageEncoding="gbk"%>

<body>
<h2>oracle分页案例</h2>
<table>
<tr><td>用户名</td><td>薪水</td></tr>
<%
       //1,加载驱动
       Class.forName("oracle.jdbc.driver.OracleDriver");
       //2,得到连接
       Connection ct=DriverManger.getConnection              ("jdbc:oracle:thin:@localhost:1521:ORCL","scott","tiger");
       //从下面开始就和其他操作是一样的
       Statement sm=ct.createStatement();
       ResultSet rs=sm.executeQuery("select * from emp");
       //在循环之前打行标记
       while(rs.next()){
       out.println("<tr>");
        //用户名
       out.println("<td>:"+rs.getString(2)+"</td>");
        //薪水
       out.println("<td>:"+rs.getString(2)+"</td>");
       out.println("</tr>");
       }
%>
</table>
</body>
</html>

------------------------------------------------------分页查询语句;
select * from 
(select al.*,rownum rn from (select * from emp) a1 where rownum<=3)
where rn>=1;
//的查询总的记录条数
 int pageCount =0;
 int  rowCount =0;
 int  pageSize =0;
ResultSet rs=sm.executeQuery("select count(*) from emp");
if(rs.next()){
 rowCount =rs.getInt(1);
 if(rowCount%pageSize==0){
   pageCount=rowCount/pageSize;
  }else{
   pageCount=rowCount/pageSize+1;
   }
}
//打印总记录数
for(int i=1;i<=pageCount;i++){
  
  out.print("<a href=mytest.jsp?pageNow="+i+">["+i+"]</a>");
}
//接受pageNow
String s_pageNow=(String)request.getParameter("pageNow");
int pageNow=1;
if(s_pageNow!=null){
 pageNow =Integer.parseInt(s_pageNow);
}
select * from 
(select al.*,rownum rn from (select * from emp) a1 where rownum<="+pageNow*pageSize+")
where rn>="+((pageNow-1)*pageSize+1)+";
-------------------------------------------------------
  写一个oracle分页实例:
<%@ page language="java" import="java.util.*,com.sql.*" pageEncoding="gbk"%>

<body>
<h2>oracle分页案例</h2>
<table>
<tr><td>用户名</td><td>薪水</td></tr>
<%
       //1,加载驱动
       Class.forName("oracle.jdbc.driver.OracleDriver");
       //2,得到连接
       Connection ct=DriverManger.getConnection              ("jdbc:oracle:thin:@localhost:1521:ORCL","scott","tiger");
       //从下面开始就和其他操作是一样的
       Statement sm=ct.createStatement();
       ResultSet rs=sm.executeQuery("select * from emp");
       //在循环之前打行标记
       while(rs.next()){
       out.println("<tr>");
        //用户名
       out.println("<td>:"+rs.getString(2)+"</td>");
        //薪水
       out.println("<td>:"+rs.getString(6)+"</td>");
       out.println("</tr>");
       }
%>
</table>
</body>
</html>
 
 
 如果Scott用户被锁:
 用dba的身份为该用户解锁
 alter user scott account unlock;
 
 passw ----修改密码
 passw scott; ---用dba身份修改scott用户的密码
 select table_name from user_tables;
 ----查看当前用户下面所拥有的对象
 select * from tab;  (得到的结果和上句类似)
 desc inf;
 conn / as sysdba;   ---sys的身份
 conn / as sysoper;
 conn system/manager;
 conn sys/change_on_install;
 create user rufus identified by rufus_123;
 alter user rufus identified by rufus;
 
--查看当前用户被授予的系统权限
select * from user_sys_privs;
--查看当前用户被授予的对象权限
select * from user_tab_privs;

--查看当前用户被授予的角色
select * from user_role_privs;
---------------------------------------------------------------
  查询阶段记住的两个查询(内嵌表,视图)
  select * from (select a1.*,rownum rn from (select * from emp) a1 where 
  rownum<=10) where rn>=6;
  
  如何查看某员工的工资等级??
  select a1.ename,a2.grade from emp a1,salgrade a2 where a1.sal between a2.losal and a2.hisal;
  
  如何查看某员工的上级领导??
  select a1.ename,a2.ename from emp a1, emp a2 where a1.mgr =a2.empno;
  
  如何查看谁是最高的领导??
  select * from emp where mgr is (not) null;
  如何查看某员工的全年收入??
 
 
 
 编写分页过程
  完成分页存储过程
  可以输入表名,每页显示记录数,当前页
  返回总记录数,总页数,和返回的结果集合
  
oracle分页
select t1.* ,rownum rn from (select * from emp) t1
select t1.*,rownum rn from (select * from emp) t1 where rownum<=10;
select * from  
(select t1.*,rownum rn from (select * from emp)t1 where rownum<=10) 
where rn>=6;

开发一个包
create or replace package testpackage as
type test_cursor is ref cursor;
end testpackage;

在分页的时候,可以把上面的sql语句当做模板使用
create or replace procedure pagi
(tableName in varchar2, -----输入的表名
pagesize in number,     -----输入每页显示的条数
pageNow in number,      -----输入要显示的当前页
myrows out number,      ------获得数据表总记录条数
myPageCount out number,  -----获得可分的总页数
p_cursor out testpackage.test_cursor  -----数据表的记录数
)is
----定义部分
----定义sql语句 字符串
v_sql varchar2(500);
----定义两个整数
v_begin number:=(pageNow-1)*pagesize+1;
v_end number:=pagesize* pageNow;
begin
----执行部分
v_sql:='select * from 
(select t1.*,rownum rn from (select * from '||tableName||')t1 where rownum<='||v_end||')
 where rn>='||v_begin;
----把游标和sql相关联
open p_cursor for v_sql;
----计算myrows和myPageCount;
v_sql:='select count(*) from '||tableName;
execute immdiate v_sql into myrows;
----计算myPageCount
if mod(myrows,pagesize)=0 then    //数学函数mod(m,n)
mypagecount :=myrows/pagesize;
else
mypagecount :=myrows/pagesize+1;
end if;
---关闭游标
---close p_cursor;
end;
---------------------------------------------------------------------
要Java测试分页过程;
public class Pagi{
 public static void main(String[] args){
   try{
    //加载驱动
   Class.forName("oracle.jdbc.driver.OracleDriver");
   Connection ct=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORCL","scott","tiger");
   //获得数据库连接
   CallableStatement cs =ct.prepareCall("{call pagi(?,?,?,?,?,?)}");
   //给?赋值
   cs.setString(1,emp);
   cs.setInt(2,5);
   cs.setInt(3,1);
   //后面三个是输出参数
    //注册总记录数
   cs.registerOutParameter(4,oralce.jdbc.OracleTypes.INTEGER);
    //注册总页数
   cs.registerOutParameter(5,oracle.jdbc.OracleTypes.INTEGER);
   //注册返回结果集
   cs.registerOutParameter(6,oracle.jdbc.OracleTypes.CURSOR);
   cs.execute();
   //取出总记录数
   int rowNum =cs.getInt(4); //中4是由该参数的位置决定的;
   int pageCount =cs.getInt(5);
   ResulSet rs=(ResultSet)cs.getObject(6);
   System.out.print("总行数="+rowNum);
   System.out.print("总页数="+pageCount);
   while(rs.next()){
      System.out.println("编号:"+rs.getInt(1)+" 姓名"+rs.getString(2)); 
     }
   }
   //关闭,最好在finally里面关闭
       }catch{
            e.printeStackTrace();
          }finally{
           //关闭各种打开的资源
            cs.close();
            ct.close();
         }
  }
}
----------------------------------------------------------------------
新的要求.薪水升序排列,取出6—10个人
改变最内层的查询语句;
v_sql:='select * from 
(select t1.*,rownum rn from (select * from '||tableName||' order by sal)t1 where rownum<='||v_end||')
 where rn>='||v_begin;
 

全局数据库名 和 sid的值是一样的
安装到最后所有的密码统一设置为oraleadmin 字母全部小写,最好不要
擅自更改;
oracle安装完成以后会自动在windows之中为用户注册若干个服务,但是
这种服务可以发现许多的是默认启动的,而这样如果配置为默认启动,则有可能
启动的速度很慢,所以建议修改为手工启动方式;
  但是在这几个服务之中,有以下两个服务是最重要的:
        监听服务: oracleoradb10g_home1TNSListener
数据库的实例服务: oracleserviceMLDN
 
以后如果有程序要操作数据库,或是一些远程的客户端要连接数据库则必须启动
此服务监听服务: oracleoradb10g_home1TNSListener
 数据库的实例服务:oracleserviceMLDN
 保证数据库的具体信息服务,每一个数据库有一个数据库实例(服务)
 命名规则:oracleServiceXXXX,其中XXX是配置的数据库(sid名称)
 监听问题:
 监听服务是oracle数据库之中使用最主要的一个服务,但是这个服务经常会出现错误,
包括以后在工作之中这个服务也会出现错误:
错误一: 注册表使了优化软件被删除了相关项;
      
  对于每一个系统服务实际上都会在注册表之中有所保存;
  把监听器全名复制,在注册表编辑器中查找oracleOraDb10g_home1TNSListener
   
错误一: 网络环境发生改变,在oracle里面,如果网络的环境出现了改变以后,有可能原始
配置的网络就无法正常的工作,此时必须进行手工的进行网络配置的修改;
  网络环境的改变最多的就是电脑名称的改变;
  【我的电脑】-->【属性】---->【计算机名】--->【更改主机名称】
  将新的主机名称改为teacher,这样一来实际计算机的网络名称就发生了改变,如果在oracle
11g 之中,这个问题可以帮助用户自动解决进行重新的配置,但是在oracle10g或者说是更早的版本
之中,这个问题只能手工解决.
  解决此问题,修改网络环境就可以了,
以后如果使用程序连接oracle 10g的话,则以上的配置有可能还是不鞥正常的访问
数据库,此时可以进入到第二步操作,进行数据库名称的注册;
  选择net manager,进入网络配置界面,
 

 序列sequence是序列号生成器,可以为表中的行自动生成序列号,产生一组等间隔的数值
(类型为数值),其主要作用是生成表的主键值,可以在插入语句中引用,也可以通过查询检查
当前的值,或使得序列增至下一个值;
 create sequence 序列名 [increment by n] [start with n] [{maxvalue/minvalue n/nomaxvalue}]
 [cycle|nocycle] [{cache n|nocache}];
 
 删除序列的语法是drop sequence 序列名;
 
 create sequence abc_seq increment by 1 start with 1 maxvalue 9999 nocyle nocache;
 如何使用自己创建的序列;
 调用nextval将生成序列中的下一个序列号,调用时候指出序列名,即为调用下面方式调用;
 序列名.nextval
----------------------------------------------------------------------------------------
 alter user scott account unlock;
 alter user scott identified by tiger;
 rownum 解决oracle中没有自动增长列的问题,为每次取出的行自动添加
 行号,rownum必须从数字1开始;
 oracle的体系结构:
 数据库的体系结构,oracle服务器提供开放的,全面和综合的信息管理,它
 由oracle数据库和oracle实例组成,一个数据库可以由多个实例使用,此时称为
 多节点数据库,但一个实例同时只能使用一个数据库;
 oracle服务器 =oracle 数据库+ oracle实例
 oracle运行的主要组件:
 用户进程--->服务器进程pga--->
 
 oracle实例是后台进程和内存结构的集合
 oracle实例分配系统全局区,启动后台进程
 实例:内存结构(sga) 共享池 // 数据缓冲区 // 日志缓冲区
 实例:后台进程:PMON,SMON,DBWR,LGWR,CKPT
 和后台进程交换文件:(实例和数据库交互)
 数据库(参数文件,口令文件,归档日志文件) --->数据文件,控制文件,日志文件
 sga 介绍:
 共享池:共享池是对sql,pl/sql程序进行语法分析编译,执行的内存区域
 共享池是由库缓存和数据字典缓存组成
 共享池的大小直接影响数据库的性能
 数据缓冲区
 用于存储从磁盘数据文件中读入的数据,所有用户共享
 服务器进程将读入的数据保存在数据缓存区中,当后续的请求需要这些数据时
 可以在内存中找到,不需要从磁盘中读取,提高了读取速度
 日志缓存区:
 日志记录数据库的所有修改信息,日志信息首先产生于日志缓冲区
 
 后台进程:
 pmon: 进程监控进程
 smon: 系统监控进程
 dbwr: 数据写入进程
  管理数据缓冲区,将最近使用过的块保留在内存中
  将修改后的缓冲区数据写入数据文件中
 lgwr: 日志写入进程
  负责将日志缓冲区中的日志数据写入日志文件
  系统有多个日志文件,该进程以循环的方式将数据写入文件
---------------------------------------------------------------------------------
创建表空间:
 
create  tablespace wh datafile 'E:\oracle\product\10.1.0\oradata\oral\wh01.dbf'
size 10 autoextend on maxsize 100m;
向表空间添加数组文件:
alter tablespace wh add datafile 'E:\oracle\product\10.1.0\iradata\orcl\wh02.dbf'
size 5m;
如何创建临时表空间
create temporary tablespace mytemp tempfile
'E:\oracle\product\10.1.0\oradata\orcl\mytemp01.dbf' size 5m;
数据文件不能跨表空间
但是数据段可以跨越数据文件,数据段也不能跨表空间存在;
删除表空间:
drop tablespace whos including contents and datafiles;
drop tablespace 表空间名 including contents and datafiles;
-----------------------------------------------------------------------------------
oracle数据库日常管理,备份,恢复,优化;
存储过程:(Oracle数据库的精华)
 
root = windows.adminstrator
 linux 的魅力就在它的图形化界面
 shotdown -h now  立刻进行关机
 shutdown -r now  现在重新启动计算机
 reboot           现在就重新启动计算机

启动
 startup mount /start up 启动实例,打开控制文件,打开数据文件

oracle 安全管理 oracle的安全管理体系
1)oracle管理数据库安全的特点
 操作系统----->用户和组
 在Oracle中------->用户和角色
 接受用户在服务器上连接上的一个请求,当检测到一个请求的时候,一旦连接成功
当Oracle安装成功以后,Oracle有一个默认的监听程序,

 理解oracle的pl/sql概念
 掌握pl/sql编程技术(包括编写过程,函数,触发器....)
 
 pl/sql是什么: 过程化语言;
 procedure language/sql 是oracle在标准的sql语言上的扩展,pl/sql不仅容许嵌入sql语言;
 还可以定义变量和常量,容许使用条件语句和循环语句,容许使用例外处理各种错误,这使得它的
 功能变得更加的强大;
 java所具有的逻辑判断功能全部具有;
 pl/sql是非常强大的数据库过程语言;
 pl/sql编写的过程,函数可以在Java程序中调用;

 学习必要性:
 提高应用程序的运行性能
 模块化的设计思想[分页的过程| 订单的过程|转账的过程--]
 减少网络传输

 写一个简单的存储过程:
 1:创建一个简单表
 2: 查看错误信息 show error;
 
SQL> create table mytest(name varchar2(30),passwd varchar2(30));
 
Table created
 
SQL> create or replace procedure sp_pro is
  2  begin
  3  insert into mytest values('rufus','m123');
  4  end;
 
 3:如何调用该过程
 exec 过程名(参数值1,参数值2,....);
 call 过程名(参数值1,参数值2,....);
 exec sp_pro;
    
create or replace sp_pro2 is
begin
----执行部分
delete from mytest where name="韩顺平";
end;
/

----调用过程
exec sp_pro2;
开发人员使用pl/sql编写应用模块时候,不仅需要掌握sql语句的编写方法,
还要掌握pl/sql语句及语法规则,pl/sql编程可以使用变量和逻辑控制语句
从而可以编写非常有用的功能模块,而且使用pl/sql编程,可以轻松完成非
常复杂的查询;

简单过程 块(编程)--->过程/函数/触发器/包
标志符号的命名规范;
1):当定义变量时候,建议使用V_ 作为前缀 v_sal;
2):当定义常量时,建议使用c_ 作为前缀 c_rate;
4):当定义例外时,建议使用 e_作为前缀 e_error;
3):当定义游标时,建议用_cursor 作为后缀 emp_cursor;

pl/sql块
块block是pl/sql的基本程序单元,编写pl/sql程序实际上就是pl/sql块,
要完成相对简单的应用功能,可能只需要编写一个pl/sql块,但是如果要想
实现复杂的功能,可能需要在一个pl/sql块中嵌套其他的pl/sql块;
块结构示意图
pl/sql块由三个部分构成:定义部分,执行部分,例外处理部分
如下所示:
declear
/* 定义部分----定义常量,变量,游标,例外,复杂数据类型*/
begin
/*执行部分---要执行的pl/sql语句和sql语句*/
exception
/*例外处理部分---处理运行的各种错误*/
special
定义部分是从declare开始的
该部分是可选的
执行部分是从begin开始的
该部分是必须的
例外处理部分是从exceptin开始的
该部分是可选的
set serveroutput off---关闭输出选项
set serveroutput on ---打开输出选项
begin 
  dbms_output.put_line('hello');
  end;
相关说明:
dbms_output是oracle所提供的包(类似Java的开发包),该包包含
一些过程,put_line就是dbms_output包的一个过程
 
declare
 v_ename varchar2(5);
begin
 select ename into v_ename from emp where empno=&no; //取出一个值赋值给变量
 dbms_output.put_line('雇员名:'||v_ename);
end;
/

会提示对话框,要输入员工号.
declare
 v_ename varchar2(5);
 v_sal number(7,2);
begin
 select ename,sal into v_ename,v_sal from emp where empno=&no; 
 dbms_output.put_line('雇员名:'||v_ename||'薪水是:'||v_sal);
end;
/

&表示要接受参数;
为了避免pl/sql程序的运行错误,提高pl/sql的健壮性,应该对可能的错误进行处理
相关说明,oracle事先预定义了一些例外,no_data_found就是找不到数据的例外;
declare
 v_ename varchar2(5);
 v_sal number(7,2);
begin
 select ename,sal into v_ename,v_sal from emp where empno=&no; 
 dbms_output.put_line('雇员名:'||v_ename||'薪水是:'||v_sal);
exception
when no_data_found then
dbms_output.put_line('你的输入不存在');
end;
/
---------------------------------------------
过程:
过程用于执行特定的操作,当建立过程时候,既可以指定输入参数in
也可以指定输出参数out,通过在过程中使用输入参数,可以将数据
传递到执行部分,通过使用输出参数,可以将执行部分地数据传递到应
用环境,在sqlplus中可以使用create procedure 命令来建立过程

--编写一个过程只要指明其数据类型就可以了
create procedure ssp_proce (spName varchar2, newSal number) is
begin
 ------执行部分
 update emp set sal=newSal where ename=spName;
end;

调用存储过程:
 call ssp_proce('SCOTT','4562');
 exec ssp_proce('SCOTT','4562');
如何在java程序中调用一个存储过程:
public staitc void main(String[] args){
 try{
//加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//得到连接
 Connection ct =DriverManger.getConnection("jdbc:oracle:thin:@localhost:152:1ORCL","scott","tiger");
//创建callableStatement;
CallableStatement cs =ct.prepareCall("{call ssp_proce(?,?)}");
cs.setString(1,"SMITH");
cs.setInt(2,10);
cs.execute();
cs.close();
ct.close();
     }catch(Exception e){
     e.printStackTrace();
  }
}

/如何使用过程返回值.
函数
函数用于返回特定的数据,当建立函数时,在函数头部必须包含return子句,而在
函数体内必须包含return语句返回的数据,我们可以使用
create function 来建立函数
create function annual_income(name varchar2)
return number is
annual_salary number(7,2);
begin
 select sal*12 +nvl(comm,0)*12 into annual_salary from emp where ename=name;
 return annual_salary;
end;
/

在sqlplus中调用函数
Function created
 
SQL> var income number ///var定义object类型的变量
SQL> call annual_income('SCOTT') into:income;
 
Method called
income
---------
54744

同样我们可以在java程序中调用该函数
select annual_income('SCOTT') from dual;
rs.getInt(1);
包
包用于在逻辑上组合过程和函数,它由包规范和包体两部分组成
我们可以使用create package命令来创建包

create or replace package sp_package is
 procedure update_sal(name varchar2,newsal number);
 function annual_income(name varchar2) return number;
end;
 
包的规范只包含了过程和函数的说明,但是没有过程和函数的实现代码,包体
用于实现包规范中的过程和函数
建立包体可以使用create package body命令
create or replace package body sp_package is
procedure update_sal(name varchar2,newsal number)
is 
begin
 update emp set sal=newsal where ename=name;
end;
function annual_income(name varchar2)
return number is 
annual_salary number;
begin
 select sal*12+nvl(comm,0) into annual_salary from emp
where ename=name;
 return annual_salary;
end;
end;

exe sp_package.update_sal('SCOTT',120);
 
 
 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值