`
足至迹留
  • 浏览: 488247 次
  • 性别: Icon_minigender_1
  • 来自: OnePiece
社区版块
存档分类
最新评论

<oracle-7> 事务

阅读更多
事务(transaction)是数据库区别于文件系统的特性之一。在文件系统中,如果你正把文件写到一半,操作系统就崩溃了,这个文件就很可能会被破坏。这正是数据库中引入事务的主要目的,事务会把数据库从一种一致状态转变为另一种一致状态。在数据库中提交工作时,可以确保要么所有修改都已经保存,要么所有修改都不保存。

Oracle中的事务体现了所有必要的ACID特征。
原子性(Atomicity):事务中的所有动作要么都发生,要么都不发生。
一致性(Consistency):事务将数据库从一种一致状态变为下一种一致状态。
隔离性(Isolation):一个事务的影响在该事务提交前对其他事务都不可见。
持久性(Durability):事务一旦提交,其结果就是永久性的。

7.1 事务控制语句
Oracle中不需要专门的语句来“开始事务”。事务会在修改数据的第一条语句隐式开始(也就是得到TX锁的第一条语句)。也可以使用set transaction或DBMS_TRANSACTION包来显式地开始一个事务,但是这一步并不是必要的,这与其他的许多数据库不同,因为那些数据库中都必须显式开始事务。如果发出commit或rollback语句(注意rollback to savepoint不会结束事务),就会显式地结束一个事务。

如果正常退出sql*plus会话,而没有提交或回滚事务,sql*plus会自动完成提交。不要过分依赖这些隐式行为,一定要显式提交或回滚。
Oracle中的事务是原子性的,这说明无非两种情况:构成事务的每条语句都会提交(成为永久)或者所有语句都回滚。注意这里的“所有”,也就是当成了一个整体。

我们可以了解到控制事务的语句只有:commit,rollback, savepoint, rollback to <savepoint>,set transaction五种。

7.2 原子性
前面对事务控制语句做了一个简要的概述后,下面可以看看语句原子性、过程原子性和事务原子性的含义。

7.2.1 语句级原子性
考虑以下语句:
insert into t values(1);
如果该语句由于一个约束冲突而失败,这一行就不会插入。不过再考虑下面的例子,表T上的一个insert或delete会触发一个触发器,它将适当地调整t2表上的列:
T2: create table t2 (cnt int);
T: create table t (x int check (x > 0));

创建触发器:
create trigger t_trigger
    before insert or delete on t for each row
    begin
        if (inserting) then
            Update t2 set cnt = cnt + 1;
        else
            update t2 set cnt = cnt – 1;
        end if;
       dbms_output.put_line(‘I fired and updated’ || sql%rowcount || ‘ rows’);
    end;
/

这种情况下往T表插入数据,会发生什么就不那么显而易见了。如果触发器触发之后出现了错误,触发器的影响是否还存在?也就是如果触发器被触发,并且更新了t2,但是这一行没有插入到T中,结果会怎样?期望的结果是,如果并没有真正在T中插入一行,我们就不希望T2中的cnt列增加。幸运的是,在oracle中,客户最初发出的语句(在这里就是insert into t)会完全成功或完全失败。这个语句是原子性的,同时insert into T的任何连带效果都被认为是该语句的一部分,这里就是触发器。

为了得到这种语句级原子性,oracle悄悄地在每个数据库调用外面包了一个savepoint。前面的insert 语句实际处理如下:
savepoint statement1;
    Insert into t values (1);
If error then rollback to statement1;
savepoint statement2;
    Insert into t values (-1);
if error then rollback to statement2;

Sybase或sqlserver中刚好相反。这些系统中的触发器会独立于触发语句执行。如果触发器遇到一个错误,它必须显式地回滚自己的工作,然后产生另外一个错误来回滚触发语句。

7.2.2 过程级原子性
有意思的是,oracle把pl/sql匿名块也当做是语句。比如以下存储过程:
Create or replace procedure p as
    Begin
        Insert into t values (1);
        Insert into t values (-1);
    End;
/

继续沿用上节的check约束,在这个过程中,第二个insert总会失败。这时候我们调用这个存储过程会发现表t里总是空的。也就是整体没有插入数据。但是如果我们调用p的时候自己捕获了错误,那第一句插入就会成功。因为oracle没有捕获到异常发生,当做事务成功,就会提交。

7.2.3 事务级原子性
事务的总目标是把数据库从一种一致状态转变为另一种一致状态。为了实现这个目标,事务也是原子性的,事务完成的所有工作要么完全提交称为永久性的,要么回滚并撤销。

7.2.4 DDL与原子性
需要指出,oracle中有一类语句具有原子性,不过只是在语句级保证原子性。DDL(数据定义语言, Data Definition Language, DDL)语句采用了一种特定的实现方式,可以完成如下工作:
(1) 提交当前所有未完成的工作,结束当前已有的所有事务。
(2) 完成DDL操作,如create table.
(3) 如果DDL操作成功则提交,否则回滚DDL操作。

7.3 持久性
通常情况下,一个事务提交时,它的改变就是永久性的。即使数据库在提交完成之后随即崩溃,你也完全可以相信这些改变确实已经永久存储在数据库中。不过,下述两种情况例外:
(1) 使用commit语句新增的write扩展(这是oracle database 10g release2及以上版本中新增的特性)。
(2) 在非分布式(只访问一个数据库,而不是多个数据库连接)pl/sql代码块中执行commit.

7.3.1 commit的write扩展
在oracle 10g release2及以上版本中,可以为commit语句增加一个write子句。这个write子句允许等到生成的redo写至磁盘之后再提交(wait,这是默认选项),或者不等写redo就直接提交(nowait)。
通常情况下,commit是一个同步过程,应用首先调用commit,然后等待整个commit处理完成。在oracle 10g release2之前,所有oracle版本支持的都是这种commit行为,这也是oracle 10g release2及以上版本的默认行为。
Oracle的当前版本中,并不需要等待提交完成(这需要一定的时间,因为提交涉及一个物理IO操作,要向存储在磁盘上的redo日志文件完成物理写操作),可以在后台完成提交。这会带来一个副作用:提交不能保证持久性。也就是说,应用可能会从该数据库得到一个响应,指出已经收到你的异步提交,而且其他会话能够看到你做出的改变,不过后来却发现你原以为已经提交的事务实际上并未真正提交。这种情况很少见,往往涉及严重的硬件或软件故障。要让一个异步提交不具有持久性,数据库必须异常关闭,这意味着数据库实例或运行这个数据库实例的计算机必须完全失效。
那么,既然事务要保证持久性,这种可能导致非持久性的特性又有什么用呢?答案在于性能。在应用中发出一个commit时,会请求LGWR进程得到生成的redo,并确保将生成的这些redo写至在线redo日志文件。完成物理IO操作的速度相当慢,所以,commit甚至比事务中DML语句本身耗时还要长。如果异步完成commit,就不再需要等待客户应用中的物理IO,这会让客户应用速度更快,特别是如果有大量commit,异步提交会让速度大大提高。
既然如此,为什么不总是使用commit write nowait呢?记住,正确性永远位于首位。只有3种特殊情况才需要使用nowait:
(1) 定制的数据加载程序。
(2) 处理某种实时数据,这些数据对时间敏感,即使失败也可能会被覆盖或丢弃。
(3) 应用实现了自己的“排队”机制。
你会注意到这3种应用个都是后台的非交互式应用,他们不会与人直接交互。如果应用需要与人交互,向用户报告“提交完成”,就应当使用同步提交。对于面向客户的在线应用,不能把异步提交作为改善性能的手段。异步提交只适应于面向批处理的应用。因此除了这3类批处理应用外,其他应用中都不该使用这个新功能—commit write nowait。

7.3.2 非分布式pl/sql代码块中的commit
从oracle6引入pl/sql以来,pl/sql一直都透明地使用异步提交。这种做法是可行的,因为从某种意义来说所有pl/sql都类似于批处理程序,即在pl/sql过程完全执行完之前,最终用户无法知道过程的结果。也正是因为这个原因,这种异步提交只能用于非分布式的pl/sql代码块;如果涉及到多个数据库,会有两个对象(两个数据库)依赖于提交的持久性。倘若两个数据库都依赖于提交的持久性,就必须采用同步协议,否则可能在一个数据库中改变已经提交,而在另一个数据库中未提交。

7.4 完整性约束和事务
默认情况下,完整性约束会在整个sql语句得到处理之后才进行检查。也有一些可延迟的约束允许将完整性约束的验证延迟到应用请求时(发出一个set constraints all immediate命令)才完成,或者延迟到发出commit时再检查。

7.4.1 immediate约束
在讨论的前一部分,我们假设约束都是immediate模式,这也是一般情况。在这种情况下,完整性约束会在整个sql语句得到处理之后立即检查。注意,这里用的是“sql语句”而不是“语句”。如果一个pl/sql存储过程中有多条sql语句,那么在每条sql语句执行之后都会立即验证其完整性约束,而不是在这个存储过程完成后才检查它。比如update语句会影响多条语句,则会在所有需要更新的语句更新完后才检查一次,而不是每变化一行数据就检查一次。

7.4.2 deferrable约束和级联更新
从oracle8开始,我们还能够延迟约束检查,对于许多操作来说,这很有好处。首先能想到的是可能需要将一个主键的update级联到子键。在以前的版本中,确实也可以完成cascade udpate,但是为此需要做大量的工作,而且存在某些限制。有了可延迟约束后,这就变得易如反掌了。

7.5 不好的事务习惯
许多开发人员在事务方面都有一些不好的习惯。例如在Informix、sybase和sqlserver中,必须显式地begin一个事务否则,每条单个的语句本身就是一个事务。Oracle在具体的语句外包了一个savepoint,采用类似的方式,哪些数据库则在各条语句外报了一个begin work/commit或rollback。这是因为,在这些数据库中,锁是稀有资源,另外读取器会阻塞写入器,反之,写入器也会阻塞读取器。为了提高并发性,这些数据库希望你的事务越小越好,有时甚至会以数据完整性为代价来做到这一点。
Oracle则采用了完全不同的方法。事务总是隐式的,没有办法“自动提交”事务,除非应用专门实现。在oracle中,每个事务都应该只在必要时才提交。事务的大小要根据需要而定。锁、阻塞等问题并不是决定事务大小的关键,数据完整性才是确定事务大小的根本。

7.5.1 在循环中提交
如果交给你一个任务,要求更新多行,大多数程序员都会力图找出一种过程性方法,通过循环来完成这个任务,这样就能提交多行。通常这样做的两个主要原因是:
(1) 频繁地提交大量小失误比处理和提交一个大事务快;
(2) 没有足够的undo空间。
这两个原因都存在误导性。另外,如果提交地太过频繁,很容易陷入危险,倘若更新做到一半时失败了,就会使你的数据库处于一种未知的状态。到目前为止,最好的办法是按业务过程的要求以适当的频度提交,并且相应地设置undo段的大小。

7.5.2 使用自动提交
关于不好的事务习惯,最后要说的是由于使用流行的编程api(odbc或jdbc)所带来的问题。这些api会默认“自动提交”(autocommit)。使用jdbc的一个好习惯是获取连接后,设置setAutocommit(false);
但是设置之后,使用更加要小心,不仅要手动commit,在失败的地方还要手动rollback,否则如果是使用了连接池,那就不会释放锁,导致锁表。还可以参考:
http://ygsilence.iteye.com/blog/1297762

7.6 分布式事务
Oracle有很多很好的特性,其中之一就是能够透明的处理分布式事务。在一个事务的范围内,可以更新多个不同数据库的数据。提交时,要么提交所有实例的更新,要么一个都不提交(它们都会回滚)。为此,我们不需要另外编写任何代码,只是提交就行了。

Oracle中分布式事务的关键是数据库链接(database link)。数据库链接是一个数据库对象,描述了如果从你的实例登陆到另一个实例。一旦建立了一个数据库链接,访问远程对象就很简单了,如下:
Select * from T@another_database;

这会从数据库链接another_database所定义数据库实例的表T中选择。一般地,你会创建表T的一个视图(或一个同义词)来隐藏T是一个远程表的事实。比如:create synonym T for T@another_database;
现在执行一个分布式事务与执行一个本地事务没什么两样:
Update local_table set x=5;
Update remote_table@another_database set y=10;
Commit;
Oracle会完成所有数据库中的提交,或都不提交。它使用了一个2PC(two-phase commit protocol,二段提交协议)来做到这一点。2PC是一个分布式协议,如果一个修改影响到多个不同的数据库,2PC允许原子性地提交这个修改。

对于分布式事务中能做的事情,还存在一些限制,这些限制是合理的:
(1) 不能在数据库链接上发出commit。也就是说,不能发出commit@remote_site,只能从发起事务的那个站点提交。
(2) 不能在数据库链接上完成DDL,因为DDL会提交,违反上面那条限制。
(3) 不能在数据库连接上发出savepoint.

0
0
分享到:
评论

相关推荐

    spring3.2+strut2+hibernate4

    &lt;prop key="hibernate.dialect"&gt;org.hibernate.dialect.Oracle10gDialect&lt;/prop&gt; &lt;prop key="hibernate.show_sql"&gt;true&lt;/prop&gt; &lt;prop key="hibernate.hbm2ddl.auto"&gt;update&lt;/prop&gt; &lt;prop key=...

    spring applicationContext 配置文件

    &lt;property name="driverClass" value="oracle.jdbc.driver.OracleDriver"/&gt; &lt;property name="jdbcUrl" value="jdbc:oracle:thin:@10.142.252.132:1521:mestest"/&gt; &lt;property name="maxPoolSize" value="10...

    Spring.html

    --全局初始化参数--&gt; &lt;context-param&gt; &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt; &lt;param-value&gt;classpath:applicationContext.xml&lt;/param-value&gt; &lt;/context-param&gt; 4.在Servlet中使用...

    ORACLE应用中常见的傻瓜问题1000问-1

    ORACLE应用中常见的傻瓜问题1000问&lt;br&gt;&lt;br&gt; 14. 如何查看系统被锁的事务时间?&lt;br&gt;&lt;br&gt; select * from v$locked_object ;&lt;br&gt;&lt;br&gt; 15. 如何以archivelog的方式运行oracle。&lt;br&gt;&lt;br&gt; init.ora &lt;br&gt;&lt;br&gt; log_...

    ssh(structs,spring,hibernate)框架中的上传下载

    5. <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> 6. <property name="url" value="jdbc:oracle:thin:@localhost:1521:ora9i"/> 7. <property name="username" value="test"/>...

    精通Oracle.10g.PLSQL编程

    使用LOB对象&lt;br&gt;16.1 LOB简介&lt;br&gt;16.2 DBMS LOB包&lt;br&gt;16.3 访问LOB&lt;br&gt;16.3.1 访问CLOB&lt;br&gt;16.3.2 访问BLOB&lt;br&gt;16.3.3 访问BFILE&lt;br&gt;16.4 习题&lt;br&gt;第17章 使用Oracle系统包&lt;br&gt;17.1 DBMS_OUTPUT&lt;br&gt;17.2...

    C#编程经验技巧宝典

    6&lt;br&gt;&lt;br&gt;0014 如何锁定窗体中的控件 6&lt;br&gt;&lt;br&gt;0015 统一窗体中控件的字体设置 7&lt;br&gt;&lt;br&gt;0016 通过“格式”菜单布局窗体 7&lt;br&gt;&lt;br&gt;0017 起始页中的“Visual Studio开发人员新闻” 7&lt;br&gt;&lt;br&gt;1.3 MSDN帮助的...

    oracle-事务oracle-transaction信息管理与信息系统.doc

    oracle-事务oracle-transaction信息管理与信息系统.doc

    ORACLE-事务ORACLE-TRANSACTION-信息管理与信息系统本科毕业设计.doc

    ORACLE-事务ORACLE-TRANSACTION-信息管理与信息系统本科毕业设计.doc

    oracle-事务oracle-transaction信息管理与信息系统学士学位论文.doc

    oracle-事务oracle-transaction信息管理与信息系统学士学位论文.doc

    Oracle Concepts 中文英文对照版 (10g R2)

    Oracle Concepts 中文版 (10g R2) 订阅 RSS&lt;br&gt; &lt;br&gt;&lt;br&gt;--------------------------------------------------------------------------------&lt;br&gt;&lt;br&gt; &lt;br&gt;Part I What Is Oracle? 第一部分 何为 Oracle? &lt;br&gt;...

    java面试800题

    &lt;type-version&gt;7.0&lt;/type-version&gt; &lt;type-storage&gt;META-INF/weblogic-cmp-rdbms-jar.xml&lt;/type-storage&gt; &lt;/persistence-use&gt; &lt;/persistence&gt; &lt;/entity-descriptor&gt; &lt;jndi-name&gt;com.ejb.CatalogHome&lt;/jndi-name...

    jdbc——内嵌事务

    &lt;property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"&gt;&lt;/property&gt; &lt;property name="defaultAutoCommit"&gt; &lt;value&gt;false&lt;/value&gt; &lt;/property&gt; &lt;/bean&gt; &lt;bean id="jdbcTemplate" class=...

    AppFramework_V1.0_New

    18.0&lt;br&gt;1.23&lt;br&gt;&lt;br&gt;1.10&lt;br&gt;&lt;br&gt;每秒插入实体&lt;br&gt;&lt;br&gt;(20次insert)&lt;br&gt;41&lt;br&gt;21&lt;br&gt;1.95&lt;br&gt;&lt;br&gt;更新实体&lt;br&gt;&lt;br&gt;(20次单条update)&lt;br&gt;27&lt;br&gt;19&lt;br&gt;&lt;br&gt;SqlMap:24&lt;br&gt;1.42&lt;br&gt;&lt;br&gt;1.13&lt;br&gt;&lt;br&gt;查询结果集(平均101...

    AppFramework_V1.0

    23.5&lt;br&gt; 15.9&lt;br&gt;&lt;br&gt;SqlMap:20.3&lt;br&gt; 1.48&lt;br&gt;&lt;br&gt;1.16&lt;br&gt; &lt;br&gt;查询结果集(平均101行)&lt;br&gt;&lt;br&gt;(1循环200次select)&lt;br&gt; 1055.1&lt;br&gt; 666.8&lt;br&gt;&lt;br&gt;不定字段:710.1&lt;br&gt; 1.58&lt;br&gt;&lt;br&gt;1.50&lt;br&gt; &lt;br&gt;&lt;br&gt; &lt;br&gt;&lt;br&gt;表...

    MLDN+李兴华+Java+Web开发实战经典.part3.rar )

    16.2.7、国际化与&lt;bean:message&gt;标签 16.3、Logic标签 16.3.1、&lt;logic:present&gt;标签和&lt;logic:notPresent&gt;标签 16.3.2、&lt;logic:empty&gt;标签和&lt;logic:notEmpty&gt;标签 16.3.3、关系运算标签 16.3.4、&lt;logic:...

    AppFramework数据库访问组件_代码生成插件_V1.1.rar

    18.0&lt;br&gt;1.23&lt;br&gt;&lt;br&gt;1.10&lt;br&gt;&lt;br&gt;每秒插入实体&lt;br&gt;&lt;br&gt;(20次insert)&lt;br&gt;41&lt;br&gt;21&lt;br&gt;1.95&lt;br&gt;&lt;br&gt;更新实体&lt;br&gt;&lt;br&gt;(20次单条update)&lt;br&gt;27&lt;br&gt;19&lt;br&gt;&lt;br&gt;SqlMap:24&lt;br&gt;1.42&lt;br&gt;&lt;br&gt;1.13&lt;br&gt;&lt;br&gt;查询结果集(平均101...

    Oracle Concepts中英文对照版(10g R2).chm

    5 章,方案对象 &lt;br&gt;Chapter 6, Dependencies Among Schema Objects 第 6 章,方案对象间的依赖关系 &lt;br&gt;Chapter 7, The Data Dictionary 第 7 章,数据字典 &lt;br&gt;Chapter 8, Memory Architecture 第 8 章,内存体系...

    java web 视频、电子书、源码(李兴华老师出版)

    16.2.7、国际化与&lt;bean:message&gt;标签 16.3、Logic标签 16.3.1、&lt;logic:present&gt;标签和&lt;logic:notPresent&gt;标签 16.3.2、&lt;logic:empty&gt;标签和&lt;logic:notEmpty&gt;标签 16.3.3、关系运算标签 16.3.4、&lt;logic:...

    李兴华 Java Web 开发实战经典_带源码_高清pdf 带书签 上

    16.2.7、国际化与&lt;bean:message&gt;标签 16.3、Logic标签 16.3.1、&lt;logic:present&gt;标签和&lt;logic:notPresent&gt;标签 16.3.2、&lt;logic:empty&gt;标签和&lt;logic:notEmpty&gt;标签 16.3.3、关系运算标签 16.3.4、&lt;logic:iterate&gt;...

Global site tag (gtag.js) - Google Analytics