设为首页 收藏本站
查看: 539|回复: 0

[经验分享] Oracle

[复制链接]

尚未签到

发表于 2016-7-27 03:02:50 | 显示全部楼层 |阅读模式
   Oracle存储过程中的事务是如何处理的?通常情况下。整个过程是作为一个事务整体被提交或回滚的,这属于数据库的基本知识,这里简单说明:
  1通常情况
通常情况下,oralce将整个存储过程作为一个事务整体,整个过程内的事务,要么都提交,要么都回滚。
如下例所示:
例1

  • SQL*Plus: Release 11.2.0.1.0 Production on 星期三 1月 4 13:24:22 2012
  • Copyright (c) 1982, 2010, Oracle.  All rights reserved.
  • 请输入用户名:  SYSTEM
  • 输入口令:
  • 连接到:
  • Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
  • With the Partitioning, OLAP, Data Mining and Real Application Testing options
  • SQL> CREATE TABLE T1 (C INT,D INT NOT NULL);
  • 表已创建。
  • SQL> create or replace procedure pt1 is begin
  •   2    insert into t1 values(1,1);
  •   3    INSERT INTO T1 VALUES(2,NULL);
  •   4    end;
  •   5  /
  • 过程已创建。
  • SQL> CALL PT1();
  • CALL PT1()
  •      *
  • 第 1 行出现错误:
  • ORA-01400: 无法将 NULL 插入 ("SYSTEM"."T1"."D")
  • ORA-06512: 在 "SYSTEM.PT1", line 3
  •  
  • SQL> SELECT * FROM T1;
  • 未选定行


  在这个例子中,我们构造了D列不允许为空的表,并故意在过程中执行一个违反约束的插入语句,造成过程调用的回滚操作,最终通过查询表T1,我们发现执行过程的时候,整个过程内的2条INSERT语句都被回滚了。这证明了在通常情况下,存储过程是作为一个事务整体的。
另一方面需要说明的是,在非自动提交的情况下,存储过程除非内部显式的执行了commit操作,否则即便整个过程执行成功,当前事务也是未提交的,这是存储过程的另一个特点:存储过程并不会自动提交。 例子如下:
例2

  • SQL> create or replace procedure pt1 is begin
  •   2    insert into t1 values(1,1);
  •   3   -- INSERT INTO T1 VALUES(2,NULL);
  •   4    end;
  •   5  /
  • 过程已创建。
  • SQL> select * from t1;
  • 未选定行
  • SQL> call pt1();
  • 调用完成。
  • SQL> select * from t1;
  •          C          D
  • ---------- ----------
  •          1          1
  • SQL> commit; --在这里显式提交
  • 提交完成。
  • SQL> select * from t1; --提交后能够看到过程插入的记录
  •          C          D
  • ---------- ----------
  •          1          1
  • SQL> call pt1();
  • 调用完成。
  • SQL> rollback; --在这里显式回滚
  • 回退已完成。
  • SQL> select * from t1; --发现回滚导致第二次执行存储过程的操作未生效
  •          C          D
  • ---------- ----------
  •          1          1
  • SQL>


  但是如果过程内部使用了commit命令或rollback命令,则存储过程就能够自行控制整个事务的结束时机,而不受整个会话的影响 。例如:
例3

  • SQL> drop table t1;
  • 表已删除。
  • SQL> create table t1(c int,d int);
  • 表已创建。
  • SQL> create or replace procedure pt1 is begin
  •   2    insert into t1 values(1,1);
  •   3      savepoint  pt1;
  •   4    insert into t1 values(2,2);
  •   5      savepoint  pt2;
  •   6    commit;
  •   7    end;
  •   8  /
  • 过程已创建。
  • SQL> truncate table t1;
  • 表已截断。
  • SQL> call pt1();
  • 调用完成。
  • SQL> select * from t1;
  •          C          D
  • ---------- ----------
  •          1          1
  •          2          2
  • SQL> rollback;-- 此时即使在过程外执行ROLLBACK,由于过程内已经COMMIT,因此这个ROLLBACK的作用范围将不会影响到过程内部。
  • 回退已完成。
  • SQL> select * from t1;
  •          C          D
  • ---------- ----------
  •          1          1
  •          2          2


  所以总结一下,我们可以在存储过程内执行COMMIT或ROLLBACK,使过程能够自行结束事务。但如果存储过程使用了异常处理呢?这个规律就不是那么显而易见了。
  
2 异常处理对事务的影响
异常处理对存储过程的事务管理有什么影响?我们看下面的例子,并先来猜一猜。
例4

  • --首先创建表
  • CREATE TABLE T1(C INT ,D INT NOT NULL);
  • --其次创建过程,其中设置了2个保存点,并包含1个异常处理器--异常处理方式很简单,直接将事务回滚到保存点PT1
  • --异常处理完成后,显式执行一个commit命令。
  • create or replace procedure pt1 is begin
  •   insert into t1 values(1,1);
  •   SAVEPOINT PT1;
  •   INSERT INTO T1 VALUES(2,2);
  •   SAVEPOINT PT2;
  •   EXCEPTION
  •    WHEN OTHERS THEN
  •     ROLLBACK TO SAVEPOINT PT1;
  •   
  •   COMMIT;
  • end;
  • CALL PT1();
  • SELECT * FROM T1; --猜一猜1:请猜猜这里的执行结果将看到什么?
  • ROLLBACK;
  • SELECT * FROM T1;-- 猜一猜2:请再猜猜这里又将看到什么结果?


  
题目出来了,请分析一下猜一猜1和猜一猜2的结果吧。
猜一猜1:这一题应该是比较简单的,我们将看到查询结果包含2条记录,正是存储过程中的2个insert语句插入的结果。
猜一猜2:由于存储过程内显式的执行了commit。因此即使再外边再执行rollback, insert 的记录也不会被回滚(类似例3),因此猜一猜2这里仍将看到与猜一猜1一样的结果。
相信不少同学将会得到如上结论。
那么果真如此吗,我们来看看实际结果:

  • SQL> truncate table t1;
  • 表被截断。
  • SQL> create or replace procedure pt1 is begin
  •   2    insert into t1 values(1,1);
  •   3    SAVEPOINT PT1;
  •   4    INSERT INTO T1 VALUES(2,2);
  •   5    SAVEPOINT PT2;
  •   6   EXCEPTION
  •   7     WHEN OTHERS THEN
  •   8      ROLLBACK TO SAVEPOINT PT1;
  •   9
  • 10    COMMIT;
  • 11  end;
  • 12  /
  • 过程已创建。
  • SQL> call pt1();
  • 调用完成。
  • SQL> select * from t1;
  •          C          D
  • ---------- ----------
  •          1          1
  •          2          2
  • SQL> rollback;
  • 回退已完成。
  • SQL> select * from t1;--我们看到了什么?2条记录被回滚掉了!
  • 未选定行


  很奇怪吧,一旦加入了异常处理,过程内部处于异常处理器之后的COMMIT命令就失效了!只有当commit处于异常处理器之前的时候才不失效(这一点同学们可以自己做实验)。
事实上,说这个commit失效也不完全,它仅仅是在不产生异常触发器的情况下才失效,当触发了异常后,这个commit就会被执行到
,如下:

  • SQL> truncate table t1;
  • 表被截断。
  • SQL> create or replace procedure pt1 is begin
  •   2    insert into t1 values(1,1);
  •   3    SAVEPOINT PT1;
  •   4    INSERT INTO T1 VALUES(2,null);
  •   5    SAVEPOINT PT2;
  •   6   EXCEPTION
  •   7     WHEN OTHERS THEN
  •   8      ROLLBACK TO SAVEPOINT PT1;
  •   9
  • 10    COMMIT;
  • 11  end;
  • 12  /
  • 过程已创建。
  • SQL> call pt1();
  • 调用完成。
  • SQL> select * from t1;
  •          C          D
  • ---------- ----------
  •          1          1
  • SQL> rollback;
  • 回退已完成。
  • SQL> select * from t1;
  •          C          D
  • ---------- ----------
  •          1          1


  没想到Oracle的异常处理会对过程内的事务提交产生这种影响?以后写这类存储过程的同学要注意了:
CREATE OR REPLACE PROCEDURE PTST IS
BEGIN
INSERT ……;
PTST2();
PTST3();
EXCEPTION
  WHEN …..THEN….
COMMIT;
END;
为了保证子过程的事务都能够完整提交,所以在主过程里面加了commit,千万要注意commit的位置,不能放在exception之后,数据库的存储过程异常处理可不是java那种try{} catch{} finally{}式的异常处理器哦。
其实从语法上讲,异常处理器应该是一个过程的最后一个组成部分,我们不应该再异常处理器之后再写别的命令。即使写了,Oracle也会报错的,如:

  • SQL> create or replace procedure pt1 is begin
  •   2       insert into t1 values(1,1);
  •   3       SAVEPOINT PT1;
  •   4       INSERT INTO T1 VALUES(2,2);
  •   5       SAVEPOINT PT2;
  •   6      EXCEPTION
  •   7        WHEN OTHERS THEN
  •   8         ROLLBACK TO SAVEPOINT PT1;
  •   9      --commit;
  • 10      insert into t1 values(3,3)
  • 11     end;
  • 12  /
  • 警告: 创建的过程带有编译错误。


  但是对于commit命令,看来Oracle是比较宽容的了。
  来源:http://www.itpub.net/thread-1563051-1-1.html
  
  pl/sql异常学习笔记
  http://www.blogjava.net/pdw2009/archive/2006/09/19/70595.html

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-249799-1-1.html 上篇帖子: Oracle——20数据库恢复与备份 下篇帖子: oracle优化:避免全表扫描
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表