oracle-事务oracle-transaction信息管理与信息系统学士学位论文.doc
xx工业大学xxx学院本科毕业设计(论文)ORACLE 事务ORACLE TRANSACTION 系 部 管理学部 专 业 信息管理与信息系统 年 级 2011 级 班级名称 11信管 1班 学 号 15041101031 学生姓名 xxx 指导教师 xxx 2015 年 5 月目 录1 ORACLE 事务12 ORACLE TRANSACTION111 ORACLE 事务 事务(Transaction)是数据库区别于文件系统的特性之一。在文件系统中,如果你正把文件写 到一半,操作系统突然崩溃了,这个文件就很可能会被破坏。不错,确实还有一些“日报式”(journaled)之类的文件系统,它们能把文件恢复到某个时间点。不过,如果需要保证两个文件同步,这些文件系统就无能为力了,倘若你更新了一个文件,在更新完第二个文件之前,系统突然失败了,就会有两个不同步的文件。这正是数据库中引入事务的主要目的,事务会把数据库从一种一致状态转变为另一种一致状态。这就是事务的任务。在数据库中提交工作时,可以确保要么所有修改都已经保存,要么所有修改都不保存。另外,还能保证实现了保护数据完整性的各种规则和检查。在上一章中,我们从并发控制角度讨论了事务,并说明了在高度并发的数据访问条件下,根据Oracle的多版本控制读一致模型,Oracle事务每次如何提供一致的数据。Oracle中的事务体现了所有必要的ACID特征。ACID是以下4个词的缩写。原子性(atomicity ):事务中的所有动作要么都发生,要么都不发生。一致性(consistency):事务将数据库从一种一致状态转变为下一种一致状态。隔离性(isolation):一个事务的影响在该事务提交前对其他事务都不可见。持久性(durability):事务一旦提交,其结果就是永久性的。这里讨论原子性的含义,以及Oracle中原子性对语句有什么影响。首先会介绍COMMIT,SAVEPOINT和ROLLBACK等事务控制语句,并讨论事务中如何保证完整性约束。我们会谈到,如果你原来一直在其他数据库中开发,可能在事务方面养成一些坏习惯(即后面所说的“不好的事务习惯”)。这里还将介绍分布式事务和两段提交(two-phase commit, 2PC)。最后会分析自治事务,指出什么是自治事务以及自治事务所扮演的角色。事务控制语句 Oracle中不需要用专门的语句来“开始事务”。事务会在修改数据的第一条语句处隐式开始(也就是得到TX锁的第一条语句)。也可以使用SET TRANSACTION或DBMS_TRANSACTION包来显式地开始一个事务,但是这一步并不是必要的,这与其他的许多数据库不同,因为那些数据库中都必须显式地开始事务。如果发出COMMIT或ROLLBACK语句,就会显式地结束一个事务。 一定要显式地使用COMMIT或ROLLBACK来终止事务;否则,你使用的工异环境就会从中挑一个来结束事务。如果正常地退出SQL*Plus会话,而没有提交或回滚事务,SQL*Plus就会认为你希望提交前面做的工作,并为你完成提交。另一方面,如果你只是退出一个Pro*C程序,就会发生一个隐式的回滚。不要过分依赖这些隐式行为,因为将来这些行为可能会有改变。一定要显式地提交或回滚事务。 ORACLE中的事务是原子性的,这说明无非两种情况:构成事务的每条语句都会提交(成为永久),或者所有语句都回滚。这种保护还延伸到单个的语句。一条语句要么完全成功,要么这条语句完全回滚。注意,我说的是“语句”回滚。如果一条语句失败,并不会导致先前已经执行的语句自动回滚。它们的工作会保留,必须由你来提交或回滚。这里谈到了语句和事务是原子性的,在具体介绍其含义之前,先来看看我们可以使用哪些事务控制语句。COMMIT:要想使用这个语句的最简形式,只需发出COMMIT。也可以更详细一些,写为COMMIT WORK,不过这二者是等价的。COMMIT会结束你的事务,并使得已做的所有修改成为永久性的(持久保存)。COMMIT语句还有一些扩展用于分布式事务中,允许增加一些有意义的注释为COMMIT 加标签(对事务加标签),以及强制提交一个可疑的分布式事务。还有一些扩展,可以让你执 行一个异步提交,这实际上违反了持久性原则。我们会在后面粗略介绍并说明其使用时机。ROLLBACK:要想使用这个语句的最简形式,只需发出ROLLBACK。同样地,你也可以更锣嗦一些, 写为ROLLBACK WORK,但是二者是等价的。回滚会结束事务,并撤销所有未提交的修改。为此 要读取存储在回滚段/undo段中的信息,并把数据库块恢复到事务开始之前的状态(后面我将把回滚段/undo段统称为undo段,Oracle Database l0g及其后版本中都喜欢用这个词)。SAVEPOINTT: SAVEPOINT 允许你在事务中创建一个标记点(marked point)。一个事务中可以有多个SAVEPOINT。ROLLBACK TO <SAVEPOINT>:这个语句与SAVEPOINT命令一起使用。可以把事务回滚到标记点,不回滚在此标记点之前的任何工作。所以,可以发出两条UPDAT语句,后面跟一个SAVEPOINT,然后又是两条DELETE语句。如果执行DELETE语句期间出现了某种异常情况,而且你捕获到这个异常,并发出ROLLBACK TO SAVEPOINT命令,事务就会回滚到指定的SAVEPOINT, 撤销DELETE完成的所有工作,而UPDATE语句完成的工作不受影响。SET TRANSACTION:这条语句允许你设置不同的事务属性,如事务的隔离级别以及事务是只读的 还是可读写的。使用手动undo管理时,还可以使用这个语句来指示事务使用某个特定的undo段,不过不推荐这种做法。我们将在第9章更详细地讨论手动和自动undo管理。就这么多,Oracle中没有别的事务控制语句了。最常用的控制语句就是COMMIT和ROLLBACK.SAVEPOINT语句的用途有点特殊。Oracle在内部频繁地使用了这个语句,实际上Oracle在执行任意SQL或PLISQL语句时都会使用这个语句,而且你会发现这个语句也用在你的应用中。原子性前面对事务控制语句做了一个简要的概述后,下面可以看看语句原子性、过程原子性和事务原子性到底有什么含义。语句级原子性考虑以下语句:看上去很明显,如果该语句由于一个约束冲突而失败,这一行就不会插入。不过,再考虑下面的例子,这里表下上的一个工NSER下或DELE下E会触发一个触发器,它将适当地调整表T2中的CNT列:ops$tkyte%ORA11GRZ> create table t2Table created.cnt intops$tkyte%ORA11GRZ> insert into tz values(o1 row created.ops$tkyte%ORA11GRZ>Commit complete.ops$tkyte%ORAiiGRZ>Table created.commitcreate table tx int check(x>0)ops$tkyte%ORA11GR2> ops$tkyte%ORA11GR2> before insert or delete on t for each row begin if(inserting)then update t2 set cnt = cnt +1; else update tz set cnt end if; dbms_ output.put_ line('I fired and updated| sql%rowcount|'rows'); end; / Trigger created.在这种情况下,会发生什么就不那么显而易见了。如果触发器触发之后出现了错误,触发器的影响是否还存在?也就是说,如果触发器被触发,并且更新了T2,但是这一行没有插入到丁中,结果会是什么?显然答案应该是,如果并没有真正在丁中插入一行,我们就不希望T2中的CNT列递增。幸运的是,在Oracle中,客户最初发出的语句(在这里就是INSERT INTOT)会完全成功或完全失败。这个语句是原子性的。以下可以验证这一点:ops$tkyte%ORA11GR2> set serveroutput onops$tkyte%ORA11GR2> insert into t values(1);I fired and updated 1 rows1 row created.ops$tkyte%ORA11GR2> insert into t values(-1);I fired and updated t rowsinsert into t values(-1)*ERROR at line 1:ORA-02290: check constraint (OPS$TKYTE.SYS_C0018o95) violatedops$tkyte%ORA11GR2> select * from t2; CNT- 1这样一来,丁中成功地插人一行,而且我们也及时地接收到消息:I fired and updated 1 row.下一个州SE盯语句违反了丁上的完整性约束。此时出现了。BMS_OUTPUT消息-T上的触发器确实触发了,这个DBMS一OUTPUT消息就是证据。触发器成功地完成了T2的更新。我们可能认为现在T2中CNT的值是2,但是可以看到它的值实际上为1 . Oracle保证最初的INSERT(即导致触发器触发的擂人语句)是原子性的,这个INSERT INTO是语句,所以INSERT INTO的任何连带效果都被认为是该语句的一部分。 为了得到这种语句级原子性,Oracle悄悄地在每个数据库调用外面包了一个SAVEPOINT。前面的两个INSERT实际上处理如下:Savepoint statement1;Insert into t values(1);If error then rollback to statements;Savepoint statement2; Insert into t values(-1);If error then rollback to statement2;对于习惯于使用Sybase或SQL Server的程序员来说,刚开始可能会有点摸不着头脑。在这些数据库中,情况恰恰相反。这些系统中的触发器会独立于触发语句执行。如果触发器遇到一个错误,它必须显式地回滚自己的工作,然后产生另外一个错误来回滚触发语句。否则,即使触发语句(或该语句的另外某个部分)最终会失败,触发器完成的工作也会持久保留。在Oracle中,这种语句级原子性可以根据需要延伸。在前面的例子中,如果INSERT INTO触发了一个触发器,这个触发器会更新另一个表,而那个表也有一个触发器,它会删除第三个表(依次类推),那么要么所有工作都成功,要么无一成功。为保证这一点,无需你编写任何特殊的代码,Oracle本来就会这么做。过程级原子性有意思的是,Oracle把PL/SQL匿名块也当做是语句。请考虑以下存储过程并且重设样例表:ops$tkyte%ORAsiGR2> create or replace procedure p 2 as 3 begin 4 insert into t values(1) 5 insert into t values(-1) 6 end; 7 /Procedure created.ops$tkyte%ORA11GRZ> delete from t;o rows deleted.ops$tkyte%ORA11GR2> update t2 set cnt=0;1 row updated.ops$tkyte%ORA11GR2> commit;Commit complete.ops$tkyte%ORA11GR2> select*from t;no rows selectedops4TKYTE%ORA11GR2> select*from t2; CNT - 0以上创建了一个过程,而且我们知道这个过程不会成功。在这个过程中,第二个INSERT总会失败。下面来看运行这个存储过程时会发生什么情况:ops$tkyte%ORA11GRZ> begin 2 p: 3 end; 4/I fired and updated a rowsI fired and updated a rowsbegin*ERROR at line 1:ORA-02290: check constraint (OPS$TKYTE.SYS_ 00018095) violatedORA-06512: at "OPS$TKYTE.P",line 5ORA-06512: at line 2ops$tkyte%ORA11GR2> select * from t;no rows selectedops$tkyte%ORA11GR2> select * from t2; CNT - 0可以看到,Oracle把这个存储过程调用处理为一个原子语句。客户提交了一个代码块BEGIN P:END; , Oracle在它外面包了一个SAVEPOINT。由于P失败了,Oracle将数据库恢复到调用这个存储过程之前的时间点。现在,如果提交一个稍微不同的代码块,会得到完全不同的结果:ops$tkyte%ORA11GR2> begin 2 P; 3 exception 4 when others then 5 dbms_output.put_ line(Error!' | sqlerrm); 6 end; 1/I fired and updated a rowsI feed and undated s rowsError!l!ORA-02290: check constraint (OPS$TKYTE.SYS_CO018095) violatedPL/SQL procedure successfully completed.ops$tkyte%ORA11GR2> select*from t; X - 1ops$tkyte%ORA11GR2> select*from t2; CNT - 1ops$tkyte%ORA11GR2> rollback;Rollback complete.在此,我们运行的代码块会忽略所有错误,这两个代码块的输出结果有显著的差别。尽管前面第一个户调用没有带来任何改变,但在这里的P调用中,第一个INSERT会成功,而且T2中的CNT列会相应地递增。Oracle认为客户提交的代码块是“语句”。这个语句之所以会成功,因为它自行捕获并忽略了错误,所以If error then rollback没有起作用,而且执行这个语句后Oracle没有回滚到SAVEPOINTO,因此,这就保留了P完成的部分工作。为什么会保留这一部分工作呢?首要的原因是P中有语句级原子性:P中的每条语句都具有原子性。P提交其两条INSERT语句时就成为Oracle的客户。每个INSERT要么完全成功,要么完全失败。从以下事实就可以证明这一点:可以看到,T上的触发器触发了两次,而且将T2更新了两次,不过T2中的计数只反映了一个UPDATE。P中执行的第二个INSERT外包着一个隐式的SAVEPOINT.事务级原子性事务(也就是一组SQL语句作为一个工作单元一同执行)的总目标是把数据库从一种一致状态转变为另一种一致状态。为了实现这个目标,事务也是原子性的,事务完成的所有工作要么完全提交并成为永久性的,要么会回滚并撤销。像语句一样,事务是一个原子性的工作单元。提交一个事务后,接收到数据库返回的“成功”消息后,你就能知道事务完成的所有工作都已经成为永久性的。DDL与原子性需要指出,Oracle中有一类语句具有原子性,不过只是在语句级保证原子性。数据定义语言(DataDefinition Language, DDL)语句采用了一种特定的实现方式,可以完成如下工作。(1)提交所有未完成的工作,结束当前已有的所有事务。(2)完成DDL操作,如CREATE TABLE。(3)如果DDL操作成功则提交,否则回滚DDL操作。这说明,只要发出CREATE, ALTER等DDL语句,就可以将现有的事务立即提交,并完成后面的DDL命令,这些DDL命令可能提交从而得到持久结果,也可能因出现错误而回滚。尽管DDL井不违反ACID概念,但DDL语句会提交的这一点确实需要注意。持久性通常情况下,一个事务提交时,它的改变就是永久性的。即使数据库在提交完成之后随即崩溃,你也完全可以相信这些改变确实已经永久存储在数据库中。不过,下述两种特定情况例外。使用COMMIT语句新增的WRIT扩展(这是。racle Database l 0g Release 2及以上版本中新增的特性)。在非分布式(只访问一个数据库,而不是多个数据库链接PLis代码块中执行COMMIT。下面来分别说明。COMMIT的WRITE扩展在Oracle Database l 0g Release 2及以上版本中,可以为COMMIT语句增加一个WRITE子句。这个WRITE子句允许等到生成的do写至磁盘之后再提交(WAIT,这是默认选项),或者不等待写redo就直接提交(NOWAIT)。NOWAIT选项是一个新功能,这个功能必须谨慎使用,你不仅要深思熟虑,而且要非常清楚它的含义。通常情况下,COMMIT是一个同步过程。应用首先调用COMMIT,然后等待整个COMMIT处理完成(有关的详细内容见第9章的介绍)。在Oracle Database 1OG Release 2之前,所有Oracle数据库版本支持的都是这种COMMIT行为,这也是Oracle Database 10G Release 2及以上版本的默认行为。在oracle的当前版本中,并不需要等待提交完成(这需要一定的时间,因为提交涉及一个物理I/O操作,要向存储在磁盘上的redo日志文件完成物理写操作),可以在后台完成提交。这会带来一个副作用:提交不能保证持久性。也就是说,应用可能会从数据库得到一个响应,指出已经收到你的异步提交,而且其他会话能够看到你作出的改变,不过后来却发现你原以为已经提交的事务实际上并未真正提交。这种情况很少见,往往涉及严重的硬件或软件故障。要让一个异步提交不具有持久性,数据库必须异常关闭,这意味着数据库实例或运行这个数据库实例的计算机必须完全失效。那么,既然事务要保证持久性,这种可能导致非持久性的特性又有什么用呢?答案在于性能。在应用中发出一个COMMIT时,会请求LGWR进程得到生成的redo,并确保将生成的这些redo写至在线redo日志文件。完成物理I/O操作的速度相当慢(这里就涉及物理I/O),因为相对来讲,将数据写至磁盘会花费很长时间。所以,COMMIT甚至比事务中DML语句本身耗费的时间还要长!如果异步完成COMMIT,就不再需要等待客户应用中的物理I/O,这会让客户应用速度更快,特别是如果有大量COMMIT,异步提交会让速度大大提高。既然如此,你可能会认为:最好总是使用COMMIT WRITE NOWAIT。毕竟,世界上最重要的东西不就是性能吗?不,绝非如此!大多数情况下都需要COMMI下默认提供的持久性。如果使用COMMIT提交并向最终用户报告“已经提交”,就需要确保所做的改变是永久的。它要记录在数据库中,即使COMMIT提交之后数据库Z硬件随即就出现了故障,也不应影响这些改变的持久存储。如果向一个最终用户报告“已下订单12 352" ,就要确保订单12 352确实已下,而且是永久的。因此,对于大多数应用来说,默认的COMMIT WRITE WAIT是唯一的正确选择(需要说明,你只需写出COMMIT即可。默认设置就是WRITE WAIT)。从Oracle 6最早引入PL/SQL以来,PL/SQL一直都透明地使用异步提交。这种做法是可行的,因为从某种意义上讲所有.PL/SQL都类似于批处理程序,即在PL/SQL过程完全执行完之前,最终用户无法知道过程的结果。也正是因为这个原因,这种异步提交只能用于非分布式的PL/SQL代码块。如果涉及多个数据库,会有两个对象(两个数据库)依赖于提交的持久性。倘若两个数据库都依赖于提交的持久性,就必须采用同步协议,否则可能在一个数据库中改变已经提交,而在另一个数据库中未提交。因此,PL/SQL会发展到采用异步提交,使得PL/SQL中的COMMIT语句不必等待物理I/O完成(从而避免旧志文件同步”等待)。这并不是说完成提交并把控制返回到应用的PL/SQL例程所做的改变都是不持久的-PL/SQL返回到客户应用之前确实会等待所生成的redo写至磁盘,不过只是在将要返回之前等待一次。2 ORACLE TRANSACTION Transactions are one of the features that set databases apart from file systems. In a file system, if you are in the middle of writing a file and the operating system crashes, that file will probably be corrupted,though there are “journaled” file systems and the like that may be able to recover your file to some pointin time. However, if you need to keep two files synchronized, such a system wont helpif you updateone file and the system fails before you finish updating the second, your files wont be synchronized.This is the main purpose of transactionsthey take the database from one consistent state to thenext. That is their function. When you commit work in the database, you are assured that either all of your changes, or none of them, have been saved. Furthermore, you are assured that the various rules and checks that protect data integrity were implemented. In the previous chapter, “Concurrency and Multi-versioning,” we discussed transactions in terms of concurrency control and how, as a result of Oracles multi-versioning, read-consistent model, Oracle transactions can provide consistent data every time, under highly concurrent data access conditions.Transactions in Oracle exhibit all of the required ACID characteristics: Atomicity: Either all of a transaction happens or none of it happens. Consistency: A transaction takes the database from one consistent state tothenext. Isolation: The effects of a transaction may not be visible to other transactions until the transaction has committed. Durability: Once the transaction is committed, it is permanent.In particular, we discussed how Oracle obtains consistency and isolation in the previous chapter.Here well focus most of our attention on the concept of atomicity and how that is applied in Oracle.In this chapter, well discuss the implications of atomicity and how it affects statements in Oracle.Well cover transaction control statements such as COMMIT, SAVEPOINT, and ROLLBACK, and well discuss how integrity constraints are enforced in a transaction. Well also look at why you may have some bad transaction habits if youve been developing in other databases. Well look at distributed transactions and the two-phase commit (2PC). Lastly, well examine autonomous transactions, what they are, and the role they play.Transaction Control StatementsYou dont need a “begin transaction” statement in Oracle. A transaction implicitly begins with the first statement that modifies data (the first statement that gets a TX lock). You can explicitly begin a transaction using SET TRANSACTION or the DBMS_TRANSACTION package, but it is not a necessary step, unlike in some other databases. Issuing either a COMMIT or ROLLBACK statement explicitly ends a transaction.You should always explicitly terminate your transactions with a COMMIT or ROLLBACK; otherwise, the tool or environment youre using will pick one or the other for you. If you exit your SQL*Plus session normally, without committing or rolling back, SQL*Plus assumes you wish to commit your work and it does so. If you just exit from a Pro*C program, on the other hand, an implicit rollback takes place.Never rely on implicit behavior, as it could change in the future. Always explicitly COMMIT or ROLLBACK your transactions.Transactions are atomic in Oracle, meaning that either every statement that comprises the transaction is committed (made permanent) or all of the statements are rolled back. This protection is extended to individual statements as well. Either a statement entirely succeeds or the statement is entirely rolled back. Note that I said the “statement” is rolled back. The failure of one statement does not cause previously executed statements to be automatically rolled back. Their work is preserved and must either be committed or rolled back by you. Before we get into the details of exactly what it means for a statement and transaction to be atomic, lets take a look at the various transaction control statements available to us: COMMIT: To use this statements simplest form, you just issue COMMIT. You could be more verbose and say COMMIT WORK, but the two are equivalent. A COMMIT ends your transaction and makes any changes permanent (durable). There are extensions to the COMMIT statement used in distributed transactions that allow you to label a COMMIT (label a transaction) with some meaningful comment and force the commit of an in-doubt distributed transaction. There are also extensions that allow you to perform an asynchronous commita commit that actually breaks the durability concept. Well take a look at this in a bit and see when it might be appropriate to use. ROLLBACK: To use this statements simplest form, you just issue ROLLBACK. Again,you could be more verbose and say ROLLBACK WORK, but the two are equivalent. A rollback ends your transaction and undoes any uncommitted changes. It does this by reading information stored in the rollback/undo segments (going forward Ill refer to these exclusively as undo segments, the favored terminology for Oracle 10g and later) and restoring the database blocks to the state they were before your transaction began. SAVEPOINT: A SAVEPOINT allows you to create a marked point within a transaction.You may have multiple SAVEPOINTS within a single transaction. ROLLBACK TO <SAVEPOINT>: This statement is used with the SAVEPOINT command.You can roll back your transaction to that marked point without rolling back any of the work that preceded it. So, you could issue two UPDATE statements, follow