Oracle中的游标、事务处理、异常

一 游标:游标(cursor)是一种PL/SQL控制结构:它可以命名一个工作区来存取该工作区的存储信息。可以非常方便的帮助我们从数据库中提取多行数据,然后可以对每一条数据进行单独处理。
1)游标的四个属性:%found      查询语句(FETCH语句)返回记录
                          %notfound   查询语句(FETCH语句)无返回记录,用于循环退出条件
                          %isopen     光标已打开标记
                          %rowcount   FETCH已获取的记录数
2)while和for语句访问游标
3)定义带参数的游标,并访问
4)定义隐式游标,并访问
          隐式游标属性
   SQL%FOUND    : SQL语句返回有记录
   SQL%NOTFOUND : SQL语句返回无记录
   SQL%ROWCOUNT : SQL语句记录总数


-----------------------------------------
eg1:while访问
declare
    v_id    tbl_student.studentid%type;
    v_name tbl_student.studentname%type;
    cursor c1 is select studentid, studentname from tbl_student where rownum <= 20;
    
begin
    open c1;--打开游标
        fetch c1 into v_id, v_name; --提取游标
        while c1%found loop --使用了%found属性
            dbms_output.put_line(v_id || '    ' || v_name);
            fetch c1 into v_id, v_name;
        end loop;
    close c1;--关闭游标
end;
---------------------------------------------
eg2:for访问
declare
    cursor c1 is select studentid, studentname from tbl_student where rownum <= 20;    
begin    --使用for时,游标不用打开、不用关闭、不用提取。直接用a1访问表的字段。a1不是游标,可以认为是指向游标的指针。
    for a1 in c1 loop
        dbms_output.put_line(a1.studentid || '    ' || a1.studentname);
    end loop;        
end;
-----------------------------------------------
eg3:for访问带参数的游标
declare    
    cursor c1(v_num number, v_sex number) is --带参数的游标
    select studentid, studentname, sex from tbl_student where (rownum <= v_num) and (sex = v_sex);    
begin    
    for a1 in c1(10, 2) loop --定义带参数的游标
        dbms_output.put_line(a1.studentid || '    ' || a1.studentname || '    ' || a1.sex);
    end loop;
end;
------------------------------------------------------
eg4:while访问带参数的游标
declare
    v_id    tbl_student.studentid%type;
    v_name tbl_student.studentname%type;
    v_sex   tbl_student.sex%type;
    cursor c1(v_num number, v_sex number) is 
    select studentid, studentname, sex from tbl_student where (rownum <= v_num) and (sex = v_sex);    
begin
    open c1(30, 1);
        fetch c1 into v_id, v_name, v_sex; --提取游标
        while c1%found loop --使用了%found属性
            dbms_output.put_line(v_id || '    ' || v_name || '    ' || v_sex);
            fetch c1 into v_id, v_name, v_sex;
        end loop;        
    close c1;    
end;
--------------------------------------------------------
eg5:for访问隐式游标
declare    
begin    
    for a1 in (select studentid, studentname, sex from tbl_student where rownum <= 20) loop
        dbms_output.put_line(a1.studentid || '    ' || a1.studentname || '    ' || a1.sex);
    end loop; 
end;

二 异常: 在PL/SQL中一个警告或错误的情形都被叫做异常。我们可以编写一段叫异常处理器的独立程序来控制出发异常。当一个异常被触发的时候,当前的块就会转到异常处理部分。

异常类型:
系统预定义的异常: 是由PL/SQL运行过程中,系统自动产生的信息。
用户定义异常:     是用户根据需要,自己定义使用的异常,执行时由用户自己引起。

预定义的异常类型:
CURSOR_ALREADY_OPEN    :    光标已经存在
VALUE_ERROR            :    值错误
NO_DATA_FOUND          :    没有找到数据
INVALID_NUMBER         :    无效数值
TOO_MANY_ROWS          :    返回太多的行
ZERO_DIVIDE            :    被0除
INVALID_CURSOR         :    无效光标
--------------------------------------------------------
eg1:系统预定义异常:NO_DATA_FOUND使用示例。
declare
    v_studentid    tbl_student.studentid%type;
begin
    select studentid into v_studentid from tbl_student where studentname='dddddd';    
exception
    when NO_DATA_FOUND then
        dbms_output.put_line('exception:no_data_found');
    when others then
        dbms_output.put_line('error!');
    
end;

自定义异常说明:
用户定义的异常必须在DECLARE段中说明,在Begin段中用RAISE引起,在EXCEPTION段中使用。
-----------------------------------------------------------
eg1:用户自定义异常
declare
    my_exception    exception;--用户自定义异常
    v_num           number := 0;
begin
    select count(*) into v_num from tbl_student where studentname='yyyy';    
    if v_num = 0 then --如果不存在符合条件的记录,引发异常
        raise my_exception; 
    else
        dbms_output.put_line('存在这个姓名的学生。'); --如果触发了异常就不会执行此语句
    end if;    
exception
    when my_exception then
        dbms_output.put_line('该学生不存在。');
    when others then
        dbms_output.put_line('error!'); 
end;
三 事务处理

事务概念:
数据库中的重要机制,确保数据完整性和并发处理的能力,它将一条或者一组sql语句当成一个逻辑上的单元,用于保障这些语句要么都成功,要么都失败。
事务的特性:
1)原子性:事务中的操作,要么全做成,要么都不做,事务是不可拆分的
2)一致性:单独运行的事务,必须保证保持数据库的一致状态
3)隔离性:多个并发事务之间不能相互干扰
4)永久性:一旦事务成功完成(Commit),它对数据库的操作是持久的

开始于第一个执行的语句:DML。
结束于以下几种情况:
1)显示执行commit/rollback;
2)执行于DDL语句或者DCL时候事物会自动提交,再rollback提交不回去了
3)正常断开的时候:
                 如exit ,transaction会自动提交
                 非正常断开的时候,如直接关闭transaction会自动回滚。
-----------------------------------------------------
eg1:事务处理示例
declare    
begin
    update tbl_accountinfo set name = 'lucy' where id = 2;
    savepoint sp1; --定义一个事务点
    delete from tbl_accountinfo where id = 2;
    rollback to savepoint sp1; --回滚到事务点sp1。
    commit;   --提交。只执行了修改,没执行删除。事务回滚了。
    
exception
    
    when others then
        dbms_output.put_line('error!');   
    
end;
---------------------------------------------------------
eg2:
declare
    v_i     scott.emp.ename%type;
begin
    update scott.emp set ename = 'macle3' where empno = 7369;
    savepoint sp1;
    select ename into v_i from scott.emp where empno=1114465461; --没有符合要求的记录
    
    if sql%notfound then --如果此事务不作if判断,依然会执行下面的rollback,commit。上面的select语句不会报错。
        dbms_output.put_line('data_not_found!'); 
    else 
        dbms_output.put_line('ok!');   
    end if; 
    rollback to savepoint sp1;
    commit;
exception    
    when no_data_found then
        dbms_output.put_line('data_not_found!');   
    
end;
-----------------------------------------------------------------
eg3:
declare
    v_i     scott.emp.ename%type;
begin
    update scott.emp set ename = 'macle3' where empno = 7369;
    savepoint sp1;
    select ename into v_i from scott.emp where empno=1114465461;--此时会跳到异常处理。事务全部执行不成功。
        
    commit;
exception    
    when no_data_found then
        dbms_output.put_line('data_not_found!');   
    
end;

原文地址:https://www.cnblogs.com/xinzhuangzi/p/4100405.html