zoukankan      html  css  js  c++  java
  • 事务处理

    事务(Transaction)

      是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割工作单位一个或者多个完成一组相关行为的SQL语句组成.通过事务,SQLServer能将逻辑相关的一组操作绑定在一起,以便服务器保持数据的完整性。
      事务通常是以BEGINTRANSACTION开始,以COMMIT或ROLLBACK结束。
      COMMIT表示提交,即提交事务的所有操作。具体地说就是将事务中所有对数据库的更新写回到磁盘上的物理数据库中去,事务正常结束。
      ROLLBACK表示回滚,即在事务运行的过程中发生了某种故障,事务不能继续进行,系统将事务中对数据库的所有以完成的操作全部撤消,滚回到事务开始的状态。
    事务的特性(ACID特性)   

         A:原子性(Atomicity)       

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

         B:一致性(Consistency)       

             事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。   

         C:隔离性(Isolation)         

            一个事务的执行不能被其他事务干扰。     

          D:持续性/永久性(Durability)     

            一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。

     -------示例------------------------------------------------------------

    创建示例表

    CREATE TABLE acc(
        ID  NUMBER(19),
        NAME VARCHAR2(20)    NOT NULL,   --不能为空
        bal   NUMBER(19,3)    NOT NULL,
        CONSTRAINT pd_id PRIMARY KEY(ID),  --主健约束
        CONSTRAINT ck_bal   CHECK(bal>=0)  --检查约束
    );
    SELECT * FROM acc;
    INSERT INTO acc VALUES(1001,'张三',3000);
    INSERT INTO acc VALUES(1002,'张三',1);

    示例一:模拟银行转账业务

    A:原子性(Atomicity)       

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

    BEGIN
      UPDATE acc SET bal=bal-4000 WHERE ID=1001;            --转出4000,但余额只有3000;
        UPDATE acc SET bal=bal-4000 WHERE ID=1001;          --转入4000
        COMMIT;                                              --提交事务
        EXCEPTION                                           --1001账户转出时会有异常,
          WHEN OTHERS THEN                                  --捕获导常
            dbms_output.put_line('账户异常,转账失败!');      --提示信息
            ROLLBACK;                                       --将数据回滚到转账前
    END;
    --查询发现数据已经回到转账前
    SELECT * FROM acc;

     B:一致性(Consistency)       

             事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。   

    DECLARE
      v_a                  acc.bal%TYPE;            --余额类型
      v_b                  acc.bal%TYPE; 
      v_sal                acc.bal%TYPE;            --计算总金额
    BEGIN
      SELECT bal INTO v_a FROM acc WHERE ID=1001;   --将账户A的余额查出
      SELECT bal INTO v_b FROM acc WHERE ID=1002;   --将账户B的余额查出
      dbms_output.put_line('转账前A的余额: '||v_a);
      dbms_output.put_line('转账前B的余额: '||v_b);
      dbms_output.put_line('转账前A和B的总余额: '||(v_a+v_b));
      
      --开始转账
      UPDATE acc SET bal=bal-2000 WHERE ID=1001;
      UPDATE acc SET bal=bal+2000 WHERE ID=1002;
      COMMIT;                                                      --提交
       SELECT bal INTO v_a FROM acc WHERE ID=1001;        --将账户A的余额查出
      SELECT bal INTO v_b FROM acc WHERE ID=1002;         --将账户B的余额查出
      dbms_output.put_line('转账后A的余额: '||v_a);
      dbms_output.put_line('转账后B的余额: '||v_b);
      dbms_output.put_line('转账后A和B的总余额: '||(v_a+v_b));
      
      EXCEPTION 
        WHEN OTHERS THEN
        dbms_output.put_line('账户异常,转账失败');
         --回退到转账前
        ROLLBACK;         
                                          
                --                         失败时账户余额  
      SELECT bal INTO v_a FROM acc WHERE ID=1001;        --将账户A的余额查出
      SELECT bal INTO v_b FROM acc WHERE ID=1002;         --将账户B的余额查出
      dbms_output.put_line('失败时A的余额: '||v_a);
      dbms_output.put_line('失败时B的余额: '||v_b);
      dbms_output.put_line('失败时A和B的总余额: '||(v_a+v_b));
    END;

    3)隔离性(Isolation):

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

    模拟银行转账

    --首先转账但不提交
    DECLARE
    BEGIN
    --开始转账
      UPDATE acc SET bal=bal-2000 WHERE ID=1001;
      UPDATE acc SET bal=bal+2000 WHERE ID=1002;
    END;
    
    --此时第二个人开始为1001账户存款
    UPDATE acc SET bal=bal+1000 WHERE ID=1001;
    --发现一直处于等待状态,
    --因为首先转账没有完成,不对同时对一个事务进行处理
    --多个用户同时处理同一事务时,要么得到的是处理前的,要么得到处理后的状态
    --这里返回转账并提交
    DECLARE
    BEGIN
    --开始转账
      UPDATE acc SET bal=bal-2000 WHERE ID=1001;
      UPDATE acc SET bal=bal+2000 WHERE ID=1002;
      COMMIT;
    END;
    --再返回第二个人存钱窗口发现已经完成,可以提交
    UPDATE acc SET bal=bal+1000 WHERE ID=1001;
    COMMIT;

    读取事务异常:

      1脏读:一个事务读取了另一个事务未提交的数据。

      2、不可重复读:一个事务再次读取之前曾经读取过的数据时,发现该数据已经被另一个已提交的事务修改。

      3、幻读:一个事务根据相同的查询条件,重新执行查询,返回记录中包含了与前一次执行查询返回的记录不同的行。

    事务的隔离级别:

    ANSI SQL-92标准中定义的事务级别:

      1、Read Uncommitted:最低等级的事务隔离,它仅仅保证了读取过程中不会取到非法数据。

      2、Read Comitted:此级别的事务隔离保证了一个事务不会读到另一个并行事务已修改但未提交的数据,此级别的事务级别避免了”脏读“。

      3、Repeatable Read:此级别的事务隔离避免了”脏读“和”不可重复读“异常现象的出现。一个事务不可能更新已经由另一个事务读取但未提交(回滚)的数据。

         4、Serializable:最高等级的隔离级别,提供了最高等级的隔离机制,三种异常情况都能避免。该事务以串行执行的方式执行。

    隔离等级

    脏读

    不可重复读

    幻读

    Read Uncommitted

    可能

    可能

    可能

    Read Comitted

    不可能

    可能

    可能

    Repeatable Read

    不可能

    不可能

    可能

    Serializable

    不可能

    不可能

    不可能

     

     

     

     

     

     

     

     

    Oracle中提供的隔离级别:

      1、Read ComittedOracle默认的隔离级别,此级别的事务保证了一个事务不会读到另一个并行事务已修改但未提交的数据,也就是说,此等级的事务避免了"脏读"。

      2、Serializable最高等级的隔离级别,提供了最高等级的隔离机制,三种异常情况都能避免。

          3、Read Only:Read Only是Serializable的子集,指事务中不能有任何修改数据库中数据的语句(DML),以及修改数据结构的语句(DDL)。只允许读不允许改。

    事务:

    Oracle中不需要专门的语句来开始事务,隐含的事务会在修改数据的第一条语句处开始

    结束事务:

    1. commit语句显式终止一个事务
    2. ROLLBACK语句回滚事务
    3. 执行一条DDL语句,如果DDL语句前面已经有了DML语句,则ORACLE会把前面的DML语句作为一个事务提交
    4. 用户断开与ORACLE连接。用户当前的事务将被自动提交
    5. 用户 进程意外终止,这里用户当前的事务被回滚

    事务控制语句:

      1、COMMIT:提交事务,对数据库的修改进行保存。

      2、ROLLBACK:回滚事务,取消对数据库所做的修改。

      3、SAVEPOINT:在事务中创建存储点。

      4、ROLLBACK TO <SAVEPOINT>:将事务回滚到存储点。

      5、SET TRANSACTION:设置事务的属性

    事务控制语句:

    SET AUTOCOMMIT=OFF

    取消自动提交

    SET AUTOCOMMIT=ON

    打开自动提交,

    COMMIT

    提交事务

    ROLLBACK

    回滚事务,取消对数据库所做的修改。

    SAVEPOINT 事务保存点的名称

    设置事务保存点

    ROLLBACK() TO [回滚点]

    回滚操作

    SET TRANSACTION

    设置事务的属性

    COMMIT 和ROLLBACEK可以写为:COMMIT WORK, ROLLBACK WORK

    SAVEPOINT 在事务中创建存储点

    语法: SAVEPOINT[SAVEPOINT_NAME]名字可以不写

    ROLLBACK TO< SAVEPOINT_NAME > 将事务回滚到指定的存储点

    事务控制语句:

    SET TRANSACTION:

    • SET TRANSACTION语句必须是事务的第一条语句
    •  指定事务的隔离级别
    •  规定事务回滚事务时使用的存储空间

    设置事务级别:必须是事务的第一条语句

    1.  SET TRANSACTION READONLY;
    2.  SET TRANSACTION ISOLATION_LEVEL READ COMMITTED;
    3.  SET TRANSACTION ISOLATION_LEVEL SERIALIZABLE;

    设置存储点

    --模拟银行转账:
    SELECT * FROM acc;
    DECLARE
    BEGIN
      UPDATE ACC SET BAL = BAL + 2000 WHERE ID = 1001; --先存入2000但不提交
      SAVEPOINT ACC_ADD; --设置存储点
      UPDATE ACC SET BAL = BAL - 6000 WHERE ID = 1001; --转出6000,余额不足会出现导演
      UPDATE ACC SET BAL= BAL + 6000 WHERE ID = 1002; --另一账户转入6000
      COMMIT; --提交
    EXCEPTION
      WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('数据异常,转账失败!');
        ROLLBACK TO ACC_ADD; --回滚到存完2000时设置的存储点
    END;
  • 相关阅读:
    inotify+rsync做实时同步
    JAVA序列化和反序列化
    初识iBatis
    《Spring in action》之高级装配
    《Spring in action》之装配Bean
    原根
    数论知识
    线性(欧拉)筛
    Codeforces Round #423 (Div. 2, rated, based on VK Cup Finals) E DNA Evolution
    Fibonacci
  • 原文地址:https://www.cnblogs.com/hjiongjiong/p/4221390.html
Copyright © 2011-2022 走看看