• oracle事务特性详解


    原子性

    事务是一个完整的操作。事务的各步操作是不可分的(原子的);要么都执行,要么都不执行。

    -- 创建表
    create table account_money
    (
      id    number(4) not null,
      name  varchar2(4) not null,
      money number(5,2) not null
    )
    ;
    -- 增加一个检查约束 
    alter table account_money
      add constraint CK_money
      check (money>=0);

    --向张三这个账号增加数据
    insert into ACCOUNT_MONEY (ID, NAME, MONEY)
    values (1001, '张三', 500.00);
    insert into ACCOUNT_MONEY (ID, NAME, MONEY)
    values (1002, '张三', 1.00);

    增加后的表如下:

           ID    NAME    MONEY
    1    1001    张三    500.00   
    2    1002    张三    1.00   

    以下为oracle事务处理

    BEGIN
      --从张三的1001账户转入张三的1002账户
      UPDATE account_money a SET a.Money=a.Money-600 WHERE a.Id='1001';
      UPDATE account_money a SET a.Money=a.Money+600 WHERE a.Id='1002';
      COMMIT;--提交事务
    EXCEPTION --异常处理
      WHEN OTHERS THEN ROLLBACK;--出现异常就回滚
      Dbms_Output.Put_Line('转账异常,转账失败');  

    在上述代码中,因为账户设置了检查约束,当账户小于0时,就会出现异常,如果不进行事务异常处理,那么第二条更新语句会被执行。当做了事务异常处理后,当出现异常就会回滚。

    image

    一致性

    在事务操作前后,数据必须处于一致状态。是一个业务规则约束的范畴。

    同样使用以上的表来做以说明:

    DECLARE
      account_a account_money.Money%TYPE;
      account_b account_money.Money%TYPE;
    BEGIN
      SELECT a.money INTO account_a FROM account_money a WHERE a.Id='1001'; 
      SELECT a.money INTO account_b FROM account_money a WHERE a.Id='1002'; 
      Dbms_Output.Put_Line('转账前A账户余额:'||account_a);
      Dbms_Output.Put_Line('转账前B账户余额:'||account_b);
      Dbms_Output.Put_Line('转账前总余额:'||(account_a+account_b));
      UPDATE account_money SET money=money-100 WHERE ID='1001';
      UPDATE account_money SET money=money+100 WHERE ID='1002';
      COMMIT;
      SELECT a.money INTO account_a FROM account_money a WHERE a.Id='1001'; 
      SELECT a.money INTO account_b FROM account_money a WHERE a.Id='1002'; 
      Dbms_Output.Put_Line('转账后A账户余额:'||account_a);
      Dbms_Output.Put_Line('转账后B账户余额:'||account_b);
      Dbms_Output.Put_Line('转账后总余额:'||(account_a+account_b));
      EXCEPTION
        WHEN OTHERS THEN
          Dbms_Output.Put_Line('转账失败,业务取消');
      SELECT a.money INTO account_a FROM account_money a WHERE a.Id='1001'; 
      SELECT a.money INTO account_b FROM account_money a WHERE a.Id='1002'; 
      Dbms_Output.Put_Line('停止转账后A账户余额:'||account_a);
      Dbms_Output.Put_Line('停止转账后B账户余额:'||account_b);
      Dbms_Output.Put_Line('停止转账后总余额:'||(account_a+account_b));
    END;

    image

    执行上段代码,

    执行第一遍:

    转账前A账户余额:500
    转账前B账户余额:1
    转账前总余额:501
    转账后A账户余额:400
    转账后B账户余额:101
    转账后总余额:501

    image

    执行第二遍:

    转账前A账户余额:400
    转账前B账户余额:101
    转账前总余额:501
    转账后A账户余额:300
    转账后B账户余额:201
    转账后总余额:501

    执行第三遍:

    转账前A账户余额:300
    转账前B账户余额:201
    转账前总余额:501
    转账后A账户余额:200
    转账后B账户余额:301
    转账后总余额:501

    。。。。。。

    当执行第5遍时:A账户的余额为0,如果再执行会出现象呢?

    转账前A账户余额:100
    转账前B账户余额:401
    转账前总余额:501
    转账后A账户余额:0
    转账后B账户余额:501
    转账后总余额:501

    执行第6遍,第7遍…………:

    转账前A账户余额:0
    转账前B账户余额:501
    转账前总余额:501
    转账失败,业务取消
    停止转账后A账户余额:0
    停止转账后B账户余额:501
    停止转账后总余额:501

    我们会发现,当我们做事务处理后,总额不会发生变化,当出现异常就不会再执行(或者说回滚)!

    隔离性

    对数据进行修改的所有并发事务是彼此隔离的,这表明事务必须是独立的,它不是以任何方式依赖于或影响其它事务。

    每个事务是独立的,我们在PL/SQL中新建两个SQL窗口就以可以做两个事务处理。

    我们还是使用以上表,表内容如下:

           ID    NAME    MONEY
    1    1001    张三    0.00
    2    1002    张三    501.00

    第一个SQL窗口:

    image

    第二个SQL窗口:

    输入:SELECT * FROM account_money;这条查询语句,我们会发现,第一个SQL窗口没有执行之前的数据。

    image

    如果我们也在第二个SQL窗口使用update更新数据会怎么样呢?

    UPDATE account_money SET money=money+300 WHERE ID='1001';
    SELECT * FROM account_money;

    他会等待第一个SQL窗口提交事务才会有更新结果!

    image

    这时我们提交第一个SQL窗口的事务,我们会看到,两个窗口的结果都发生变化。

    image

    我们再提交第二个SQL窗口的事务(在第一个SQL窗口事务没有提交之前是不能提交第二个窗口的事务的),结果也同上图!

    持久性

    事务完成后,它对数据库的修改被永久保存下来。

  • 相关阅读:
    笔记:端子镀金厚度
    笔记:C 编译过程
    抽象类与接口类
    面向对象的三大特性之继承
    类命名空间与对象、实例的命名空间 面向对象的组合用法
    初识类和对象
    面向过程与面向对象
    初识面向对象
    hashlib模块configparser模块logging模块
    collections模块和os模块
  • 原文地址:https://www.cnblogs.com/javalittleman/p/4161824.html
Copyright © 2020-2023  润新知