plsql programming 14 DML和事务管理
我们可以把多个SQL语句集中在一起, 在逻辑上组成一个事务, 从而保证这些操作或者全部被保存到数据库(用sql的说法就是”提交”), 或者被整体驳回(用sql的说法是“回滚”).
事务: ACID
原子性: 改变或者全部发生, 或者全部不发生.
一致性: 正确的状态转换, 不能违反任何完整性约束, 例如 银行汇款
隔离: 从任何一个事务的角度来看, 其他事务看起来都是在它之前或之后发生的.
持久性: 一旦一个事务成功结束, 状态的改变就是永久的了.
DML 语句, insert, update, delete, merge (具体细节已经熟悉, 这里就不罗列了)
DML 操作的游标属性
oracle 准许我们通过一些特殊的隐式游标属性访问最后一次运行的隐式游标的信息.
利用隐式游标属性可以得到最近执行的 insert, update, delete, merge 或者 select into 语句的返回信息.
首先, 隐式游标属性的值总是属于最后一次执行的 sql 语句, 而不管隐式游标是在哪一个块中执行. 在oracle会话打开第一个sql游标之前, 所有隐式游标属性都是 null.(%ISOPEN是个例外, 这个属性返回false)

1: -- chap14_01.sql 看究竟修改了多少条记录
2: create or replace procedure change_author_name( old_name_in in books.author%type,
3: new_name_in in books.author%type,
4: rename_count_out out pls_integer)
5: is
6: begin
7: update books
8: set author = new_name_in
9: where author = old_name_in;
10:
11: rename_count_out := sql%rowcount; -- 只针对DML改变的计数
12: end;
13: /
14: show errors;
假设我们在做 delete, update 等 DML 操作时, 我们还需要提取一些信息做另外处理, 这时我们不用另外的select语句, 直接使用 returning 语句, 就可以提取我们想要的信息, 要知道另外的select语句是需要另外建立游标的, 所以我们这样做减少了游标数量, 降低了CPU的消耗, 参考下例: ( returning 当前游标的任何列 )
1: declare
2: myname employees.last_name%type;
3: mysal employees.salary%type;
4: begin
5: for rec in (select * from employees) -- 行记录, 也不需要定义
6: loop
7: update employees
8: set salary = salary * 1.5
9: where employee_id = rec.employee_id
10: returning salary, last_name into mysal, myname; -- 以前没用过, 可以return当前游标的任何列
11:
12: dbms_output.put_line('New salary for ' || myname || ' = ' || mysal);
13: end loop;
14: end;
15: /
不仅可以将内容返回在变量中, 当 dml 操作多余 1 条记录时, 也可以将结果返回给一个集合, 使用批量绑定技术, 以前也没用过, 向后再确认吧. 貌似用不到
DML 和 异常处理
- 如果我们的代码使用的是自治事务, 发生异常时必须要执行一个回滚或者提交
- 我们可以通过保存点来控制回滚范围
- 如果一个异常传播到最外层的代码块(也就是说”未处理”的异常), 大多数pl/sql宿主执行环境, 比如 sql*plus, 会自动进行回滚, 所有变化都会被撤销.
DML 和 记录
1: create or replace procedure set_book_info( book_in in books%rowtype)
2: is
3: begin
4: insert into books values book_in;
5: exception
6: when dup_val_on_index then
7: update books set row = book_in
8: where isbn = book_in.isbn;
9: end;
10: /
11: show errors;
上例中, 居然可以直接使用 set row = book_in, 直接整行进行更改…
在 returning 中也可以使用一整行, 例如:
returning isbn, title, summary, author, date_published, page_count into my_book_return_info
( my_book_return_info 类型是 books%rowtype; )
事务管理
commit : 提交
rollback : 回滚
rollback to savepoint : 撤销从指定的保存点以来的所有改变, 并释放这一部分代码使用的锁资源
savepoint : 创建一个保存点, 有了保存点之后我们就可以进行部分回滚操作( SAVEPOINT savepoint_name)
set transaction : 让我们可以启动一个只读或者读写会话, 构建一个隔离级别, 或者为当前的事务分配一个专门的会滚段. (用处不大, 不用理会, 就用默认的就可以了)
lock table : 让我们用指定的模式锁定整个数据库表, 这个命令覆盖了表缺省使用的行级锁. (用处不大)
在我们执行 DML 之前, plsql 都会隐含的生成一个保存点. 如果这个dml语句失败, 会自动放生一个回滚动作, 回滚到隐含的保存点.
set transaction read only :
这个语句把当前事务定义为只读, 在一个只读事务中, 后续的查询能看到的只是在事务开始之前已经提交的变化, 当我们执行一个运行时间很长的, 多个查询组成的报表时, 我们希望确保报表中的数据是一致的, 这个语句就非常有用.
set transaction read write : ( 缺省设置 )
LOCK TABLE table_reference_list IN lock_mode MODE[NOWAIT];
lock_mode : ROW SHARE, ROW EXCLUSIVE, SHARE UPDATE, SHARE, SHARE ROW EXCLUSIVE, EXCLUSIVE
我们应该尽可能地依靠 oracle 缺省的锁定行为, 应用程序应该把 lock table 作为最后一根稻草, 小心使用.
自治事务(个人感觉, 没什么用处, 先放着, 还是有一些用处)
在后面的触发器, 以及动态执行sql语句时, 可以用到自治事务.
触发器: 将触发器的动作写到一个自治事务中, 这样可以独立于操作的DML本身操作的事务管理.
动态SQL: 因为动态SQL可以执行DDL, 而DDL是自动提交的, 这样, 如果在DDL之前有一些DML, 而我们不想提交这些DML操作, 就可以通过自治事务, 将DDL独立起来.
一个PLSQL块被叫做自治事务, 我们实际是把这个块中的DML语句和调用程序的事务环境完全的隔离开. 这个块就称为一个由其他事务启动的独立的事务, 前一个事务就叫做主事务, 在自治事务中, 主事务是挂起的, 即 主事务调用自治事务, 我们执行 sql 操作, 提交或回滚这些操作, 然后重启主事务.

自治事务, 类似 linux 中的 shellscript . 个人感觉: 所谓主事务重启, 其实就是中断返回.
定义自治事务:
PRAGMA AUTONOMOUS_TRANSACTION; -- 在声明部分 ;
这个编译指令告诉PLSQL编译器把一个PLSQL块编译成自治的或者独立的. 作为自治事务, 可以是下面中的一种:
- 最顶层(不是嵌套的)匿名PLSQL块(这样, 这个块就是一个自治事务)
- 函数或过程, 或者在一个包里定义或者是一个独立的程序(这样, 这个过程和函数就是自治事务)
- 对象类型的方法(函数或过程)
- 数据库触发器(这样, 这个触发器所触发的操作就是自治事务)
自治事务规则和限制
- 如果自治事务要访问的资源已经被主事务(主事务已经暂停, 要等自治过程退出才能继续)持有, 我们的程序就放生了死锁. 例如:
procedure update_salary(dept_in IN number)
is
PRAGMA AUTONOMOUS_TRANSACTION;
cursor myemps is
select empno from emp
where deptno = dept_in
for update nowait;
begin
for rec in myemps loop
update emp set sal = sal * 2
where empno = rec.empno;
end loop;
commit; -- 因为是自治事务
end; -- 运行
begin
update emp set sal = sal * 2;
update_salary(10);
end;
以上代码的运行部分在一个块内, 以上代码运行时, 会出错. 因为上例中, 资源已经被主事务所占有, 即 update 已经修改了 emp 表, 这时候如果自治事务再去抢夺主环境已经占有的资源, 就会出错.
- 我们不能只用一个 PRAGMA 声明就把一个包中的所有子程序(或者一个对象类型中的所有方法)全部标成自治的, 我们必须对位于包体的每个程序的声明单元都明确的指定自治事务. 这个规则的一个后果是我们无法通过包规范来区分到底哪一个程序是自治事务的.
- 如果想从一个已经执行了至少一个 insert, update, merge, delete 语句的自治事务程序没有任何错误的退出, 我们必须明确的执行一个提交或者回滚.
- commit 和 rollback 语句只结束了活动的自治事务, 但不会终止自治例程, 即程序还要继续向下走(这是当然)实际上, 我们可以在一个自治块中使用多个commit或rollback.
- 我们只能回滚到当前会话创建的保存点, 如果是在一个自治事务中, 我们不能回滚到主事务创建的保存点.
- 数据库参数文件中的 TRANSACTIONS 参数指定的是一个会话内可以并发的最大事务数量.
事务的可见性
自治事务的缺省行为是, 只要在自治事务中执行了 commit 或者 rollback, 这些改变立即对主事务可见, 但是如果我们想对主事务隐藏, 就需要设置 set transaction isolation level serializable; 这个设置影响整个会话.
什么时候使用自治事务
只要我们想把模块内的修改和外层调用者的事务环境隔离开, 就需要对我们的程序模块定义自治事务.
日志机制: 一方面我们需要把错误信息保存(commit), 另一方面, 我们需要回滚当前错误所造成的数据库数据错误(rollback)
触发器执行提交和回滚: 通过把触发器定义成自治事务, 我们就可以在触发器内部执行提交和回滚, 而不影响触发该触发器的事务, 比如, 我们想对表上的每一个操作进行跟踪, 不管这个操作完成与否, 我们甚至还想知道哪些操作失败了.
可重用的应用组件: 自治事务的核心价值, 现在的internet世界已经分散的多层架构, 用不影响调用环境的独立工作单元处理任务变得越来越重要.
避免查询时出现突变表触发器错误: 如果一个行级触发器中试图读取或者写入触发表就会发生突变表触发器错误. 不过, 如果通过使用 PRAGMA AUTONOMOUS_TRANSACTION 让触发器成为自治事务, 并且在触发器内部提交, 我们就可以查询出发表的内容( 只是查询, 不能修改)
在修改这个表的SQL中调用用户自定义函数:
重试计数器: 假设我们在彻底拒绝用户对某个资源的访问之前, 准许用户做 N 次尝试.
plsql programming 14 DML和事务管理的更多相关文章
- AOP基本概念、AOP底层实现原理、AOP经典应用【事务管理、异常日志处理、方法审计】
1 什么是AOP AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件 ...
- Spring基于AOP的事务管理
Spring基于AOP的事务管理 事务 事务是一系列动作,这一系列动作综合在一起组成一个完整的工作单元,如果有任何一个动作执行失败,那么事务 ...
- 已禁用对分布式事务管理器(MSDTC)的网络访问。请使用组件服务管理工具启用 DTC 以便在 MSDTC 安全配置中进行网络访问。
今天写ASP.NET程序,在网页后台的c#代码里写了个事务,事务内部对一张表进行批量插入,对另外一张表进行查询与批量插入. 结果第二张表查询后foreach迭代操作时报错:已禁用对分布式事务管理器(M ...
- Spring第13篇—–Spring整合Hibernate之声明式事务管理
不容置疑的我们可以知道Spring的事务管理是通过AOP(AOP把我们的事务管理织入到我们的业务逻辑里面了)的方式来实现的,因为事务方面的代码与spring的绑定并以一种样板式结构使用.(面向切面编程 ...
- MySQL存储过程之事务管理
原文链接:http://hideto.iteye.com/blog/195275 MySQL存储过程之事务管理 ACID:Atomic.Consistent.Isolated.Durable 存储程序 ...
- Spring高级事务管理难点剖析
1Spring事务传播行为 所谓事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播.Spring支持7种事务传播行为 PROPAGATION_REQUIRED(加入已有事务) 如果当前没 ...
- JDBC 学习笔记(四)—— 自定义JDBC框架+Apache—DBUtils框架+事务管理+操作多表
本文目录: 1.自定义JDBC框架 ——数据库元数据:DataBaseMetaData 2.自定义JDBC框架 ——数据库元数据:DataBaseMetaData ...
- Spring 事务管理高级应用难点剖析--转
第 1 部分 http://www.ibm.com/search/csass/search/?q=%E4%BA%8B%E5%8A%A1&sn=dw&lang=zh&cc=CN& ...
- MyBatis5:MyBatis集成Spring事务管理(上篇)
前言 有些日子没写博客了,主要原因一个是工作,另一个就是健身,因为我们不仅需要努力工作,也需要有健康的身体嘛. 那有看LZ博客的网友朋友们放心,LZ博客还是会继续保持更新,只是最近两三个月LZ写博客相 ...
随机推荐
- Word2010插入页码分节符
不是分页符,分节符主要是为了插入前后两种不同类型的页码,比如前面查罗马数字,从目录开始插入阿拉伯数字.
- CSS3:绘制图形
CSS画图形,基本上所有的实现都是对边框的角度的调整及组合. 以下不包含兼容浏览器的前缀,请使用时在border-radius前加-moz-.-webkit- .... 1.正常得不得了的矩形 .sq ...
- 更改Windows用户文件夹(Users)默认位置到其它盘
一.把 C盘Users文件夹里的用户数据,迁移到D盘Users文件夹中 系统环境:windows7 1.mklink命令详解 C:>mklink 创建符号链接. MKLINK [[/D] | [ ...
- VR/AR工作原理、目前存在的技术问题
http://blog.csdn.net/liulong1567/article/details/50686558 摘要: 这些挑战,每一个都还需要很多努力才能解决.目前它们很多都还不到量变(只是需要 ...
- Chrome 37 Beta: 使用Windows的DirectWrite和支持<dialog>元素
今天的Chrome Beta 发布版包含了许多新的开发者特性.这些特性帮助你制作更丰富的.更迅速的和更引人入胜的网页内容以及应用程序,尤其是移动设备上.除非特别指出,否则下面描述的变化对Android ...
- Android动态载入Dex机制解析
1.什么是类载入器? 类载入器(class loader)是 Java™中的一个非常重要的概念.类载入器负责载入 Java 类的字节代码到 Java 虚拟机中. Java 虚拟机使用 Java 类的方 ...
- $ gulp watch 运行出错解决方法
$ gulp watch 运行出错解决方法 $ gulp watch 如果你出现了如下报错信息: gulp-notify: [Laravel Elixir] Browserify Fail ...
- 【Excle】两个表格多列数据对比,找出差异
现在有表格如下,差异A中的红色标记为区域1在区域2中找不到对应的值,差异B中的红色标记为区域2在区域1中找不到对应的值 那么怎么去查找呢? 这里用到COUNTIF跟数组公式 C3=SUM(COUNTI ...
- jmeter 之 BSF,BeanShell(转载)
jmeter无法自行处理javascript,但是它可以用自带的BSF PreProcessor(BSF:面向java的脚本语言,支持javascript) (使用这个之前要把bsh-2.0b2.ja ...
- AR路由器web界面每IP限速配置方法
一.做下载方向的限速:在 QOS>接口限速,选择“新建”“接口名称”选择内网接口“限速类型”选择IP限速(目的)“方向”选择流出“起始/目的ip”写内网的ip“类型”选择独占“承诺速率”为限速的 ...