zoukankan      html  css  js  c++  java
  • 浅谈Oracle事务【转载竹沥半夏】

    浅谈Oracle事务【转载竹沥半夏】

    所谓事务,他是一个操作序列,这些操作要么都执行,要么都不执行,是一个不可分割的工作单元。通俗解释就是事务是把很多事情当成一件事情来完成,也就是大家都在一条船上,要死一起死,要活一起活。

      为什么要引入事务?事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。事务结束后,能保证数据库数据的一致性。例如银行转账,一个账号扣钱,一个账号增款,要么都执行,要么都不执行,不能只执行一条,否则会出现账款错误。这样我们就可以体会到事务的重要性了吧。其实在我们的生活中,很多事情都是要组成事务来执行的。既然它那么重要,下面我们就来深入的了解一下什么是事务吧。

    一.事务的四个特征ACID

      事务的四个特征非常重要,只有满足这些特征,才能保证事务执行后只有一个结果:要么成功,要么失败。

      (1)原子性(Atomicity):组成事务处理的语句形成了一个逻辑单元,不能只执行其中的一部分。

      (2)一致性(Consistemcy):事务处理前后,数据处于一致状态,保证数据的无损。

      (3)隔离性(Isolation):对数据进行修改的多个事务是彼此隔离的,互不影响。

      (4)持久性(Durability):事务完成之后,它对于系统的影响是永久的,该修改即使出现系统故障也将一直保留,真实的修改了数据库。

      示例一

    复制代码
    ---------创建表
    CREATE TABLE bank
    (
        customerName CHAR(10),          --顾客姓名
        currentMoney number(10)         --当前余额
    );
    ---------添加余额不能小于1的约束
    ALTER TABLE bank ADD CONSTRAINT CK_currentMoney CHECK(currentMoney >= 1);
    ---------插入测试数据
    INSERT INTO bank(customerName, currentMoney) VALUES('张三', 1000);
    INSERT INTO bank(customerName, currentMoney) VALUES('李四', 1);
    commit;
    select * from bank;
    ---------不使用事务完成转帐操作(总金额异常)
        update bank set currentMoney=currentMoney-1000 where customerName='张三';
        update bank set currentMoney=currentMoney+1000 where customerName='李四';
    commit;
    ---------清空数据,
    delete bank;
    select * from bank;
    ---------使用事务完成转账操作不会出现总金额异常
    set serveroutput on;
    declare
     li_money number(10):=0;
    begin
      update bank set currentMoney=currentMoney+1000 where customerName='李四';
      select currentMoney into li_money  from bank where customerName='李四';
       dbms_output.put_line('李四当前的余额是:'||li_money);
      update bank set currentMoney=currentMoney-1000 where customerName='张三';
    exception
      when others then
        dbms_output.put_line('撤销提交');
        rollback;
    end;
    --转帐之后查看结果,李四的钱被回滚回去了
    select * from bank;
    复制代码

    二.回滚到保存点

      (1)rollback:回滚到最初状态,可以参考示例一。

      (2)rollback to 保留点:回滚到保留点。

      示例二

    复制代码
    declare
      num int;
    begin
      savepoint a; --创建保存点a
      update bank set currentmoney=currentmoney-100 where customername='张三';
      savepoint b; --创建保存点b
      update bank set currentmoney=currentmoney+100 where  customername='李四';
      savepoint c; --创建保存点c
      num:=# --从提示框接收一个数据,用于操作回滚到哪一点。
      insert into bank values('王五',600);
      savepoint d; --创建保存点d
      if num=1 then 
        rollback to a; --当提示框中输入1时,回滚到保存点a,即全部回滚,相当于rollback;
      elsif num=2 then 
        rollback to b; --当提示框中输入2时,回滚到保存点b
      elsif num=3 then 
        rollback to c; --当提示框中输入3时,回滚到保存点c
      else 
        rollback to d; --其他情况下,回滚到保存点d
      end if;
    end;
    复制代码

    三.事务的隔离级别

      从上面的示例中我们可以看到事务带给我们的巨大好处,保证了数据的一致性,但是,仅仅有保证用事务执行就可以保证数据前后是一致的吗?在实际情况下,事务是并发执行的,不可避免的会出现多个事务同一时间对相同数据的操作,这样就会产生各种并发问题。

      并发问题:(1)脏读:事务T1、T2,T1读取了T2已经更改但还没有提交的数据,之后,若T2回滚,T1读到的数据就是临时无效的脏数据。

            (2)不可重复读:事务T1、T2,T1读取了一个字段,然后T2更新了该字段,当T1再次读取该字段时,值就不同了。

            (3)幻读:事务T1、T2,T1读取了一个字段,T2在在该表中又插入了一些字段,当T1再次读取时,会多出几行。

      为了解决上面这些问题,引入了隔离级别,显然,隔离级别是指一个事务与其他事务的隔离程度,隔离级别都有哪些呢,下面简单介绍了一下。

    隔离级别 描述
    read uncommitted(读取未提交数据) 允许事务读取未被其他事务提交的变更,脏读、不可重复读和幻读问题都会出现。
    read committed(读取已提交数据) 只允许事务读取已被其他事务提交的变更,可以避免脏读,但不可重复读和幻读问题仍然存在。
    repeatable committed(可重复读) 确保一个事务可以多次从一个字段中读取到相同的值,避免了脏读、不可重复读,但幻读问题仍然存在。
    serializble(串行化) 在这个事务执行期间,禁止其他表对该表的插入、删除、修改操作,所有并发问题都可以避免,但性能低下。
       Oracle 支持的 2 种事务隔离级别:READ COMMITED, SERIALIZABLE。在 Oracle 默认的事务隔离级别为: READ COMMITED。Oracle同时提供了一个Read only的隔离级别。
      虽然隔离级别可以避免并发问题,但是要酌情使用,毕竟隔离级别越高,并发性就越弱,这样软件的性能就降低了。
    四.总结
      (1)事务只有一个执行结果,要么成功,要么失败。
      (2)事务的四个特点:原子性、一致性、隔离性和持续性。
      (3)事务的执行过程中发生问题时,可以直接回滚到最初未执行之前的数据状态,也可以通过savepoint设置保存点,回滚到特定的保存点位置。
      (4)当多个事务同时访问相同数据时,可能产生并发问题,为了避免这些问题,引入了隔离级别。但是隔离级别越高,虽然数据一致性越好,但是并发性却更弱。所以要酌情使用。
     
  • 相关阅读:
    Oracle PL/SQL 性能分析工具 profiler 说明
    Oracle 传输表空间(Transportable Tablespaces) 示例(一) 跨操作系统迁移表空间 (endianness 格式相同)
    Oracle 传输表空间(Transportable Tablespaces) 示例(二) 跨操作系统迁移表空间(endianness格式不同)
    Oracle 跨操作系统 迁移 说明
    Oracle 11g ORA00845: MEMORY_TARGET not supported on this system 说明
    Oracle Tablespace Map 功能 说明
    Oracle 11g ORA00845: MEMORY_TARGET not supported on this system 说明
    Oracle 传输表空间(Transportable Tablespaces) 示例(一) 跨操作系统迁移表空间 (endianness 格式相同)
    Oracle Convert a 32bit Database to 64bit Database(32位 转到 64位)说明
    Oracle Instant Client 使用 说明
  • 原文地址:https://www.cnblogs.com/bzx888/p/4822446.html
Copyright © 2011-2022 走看看