SQL基础15——数据库事务(TRANSACTION)

一、数据库事务

    数据库事务是指作为单个逻辑工作单元执行的一系列操作,可以认为事务就是一组不可分割的SQL语句

   

二、数据库事务的ACID属性

    原子性(atomic)

       事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。

 

    一致性(consistent)

       事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务

        的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如B 树索引或双向链

        表)都必须是正确的。

 

    隔离性(insulation)

       由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。事务查看数据时数据所处的状

        态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中

        间状态的数据。

 

    持久性(Duration)

       事务完成之后,它对于系统的影响是永久性的。

 

三、事务的组成

    一个数据库事务可由:

       一个或多个DML语句组成

       一个DDL语句组成

       一个DCL语句组成

 

    一个数据事务由:

       以第一个DML语句的执行作为开始

       以下面的其中之一作为结束

           commit     (提交)

           rollback   (回滚)

           ddl或dcl语句   (自动提交)

           用户会话正常结束(自动提交) 

           系统异常终止 (自动回滚)

           系统崩溃 (自动回滚)

 

四、事务的提交或回滚(COMMITROLLBACK)       

    --使用COMMIT事务,robinson记录被插入到表

       SQL> INSERT INTO scott.emp(empno,ename,job,salary)

         2  VALUES(9999,'Robinson','DBA',3500);

 

       1 row created.

 

       SQL> COMMIT;

 

       Commit complete.

 

       SQL> UPDATE scott.emp SET salary = 4000 WHERE ename = 'Robinson';

 

       1 row updated.

 

    --使用ROLLBACK回滚,更新将失效,最终结果如下面的查询

       SQL> ROLLBACK;

 

       Rollback complete.

 

       SQL> SELECT * FROM scott.emp WHERE ename = 'Robinson';

 

            EMPNO ENAME                          JOB              MGR HIREDATE      SALARY     DEPTNO

       ---------- ------------------------------ --------- ---------- --------- ---------- ----------

             9999 Robinson                       DBA                                  3500 

 

五、保存点

    设置保存点:

       SAVEPOINT NAME

    恢复至保存点:

       ROLLBACK TO NAME

 

    --查看empno为,的记录  

       SQL> SELECT * FROM scott.emp WHERE empno IN (1235,1236);

 

            EMPNO ENAME                          JOB              MGR HIREDATE      SALARY     DEPTNO

       ---------- ------------------------------ --------- ---------- --------- ---------- ----------

             1235 Tony                           boy                  28-JUN-10       7100

             1236 Ben                            IT                   28-JUN-10       3100         20

 

    --首先更新empno 为的salary ,并设置了一个保存点tran1     

       SQL> UPDATE scott.emp SET salary = salary * 1.5 WHERE empno = 1236;

 

       1 row updated.

 

       SQL> SAVEPOINT tran1;

 

       Savepoint created.

 

    --更新empno 为的salary

       SQL> UPDATE scott.emp SET salary = salary * 0.8 WHERE empno = 1235;

 

       1 row updated.

 

    --查看刚刚更新的两条记录

       SQL> SELECT * FROM scott.emp WHERE empno IN (1235,1236);

 

            EMPNO ENAME                          JOB              MGR HIREDATE      SALARY     DEPTNO

       ---------- ------------------------------ --------- ---------- --------- ---------- ----------

             1235 Tony                           boy                  28-JUN-10       5680

             1236 Ben                            IT                   28-JUN-10       4650         20

 

    --将事务回滚到保存点tran1

       SQL> ROLLBACK TO SAVEPOINT tran1;

 

       Rollback complete.

 

    --可以看到保存点之后的修改被回滚,而保存点之前的修改则不受影响

       SQL> SELECT * FROM scott.emp WHERE empno IN (1235,1236);

 

            EMPNO ENAME                          JOB              MGR HIREDATE      SALARY     DEPTNO

       ---------- ------------------------------ --------- ---------- --------- ---------- ----------

             1235 Tony                           boy                  28-JUN-10       7100

             1236 Ben                            IT                   28-JUN-10       4650         20

 

    --对所作的修改全部ROLLBACK,此时仅仅包含了empno 为的记录,因为已经被回滚

       SQL> ROLLBACK;

 

       Rollback complete.

 

       SQL>  SELECT * FROM scott.emp WHERE empno IN (1235,1236);

 

            EMPNO ENAME                          JOB              MGR HIREDATE      SALARY     DEPTNO

       ---------- ------------------------------ --------- ---------- --------- ---------- ----------

             1235 Tony                           boy                  28-JUN-10       7100

             1236 Ben                            IT                   28-JUN-10       3100         20

     

六、事务的开始与结束及不同时刻的状态

    事务的开始

       连接到数据并执行了一条DML语句(INSERT ,UPDATE,DELETE)

       前一条事务结束后,又执行了另外一条DML语句

    事务的结束

       执行COMMIT 或ROLLBACK

       执行DDL语句,则自动提交并结束事务

       执行DCL语句,则自动提交并结束事务

       断开与数据库的连接,如退出SQL Plus。

           Windows下SQL Plus正常退出将执行COMMIT,如点击关闭窗口直接关闭则回滚

           X-Window下SQL Plus正常退出将执行COMMIT,如点击关闭窗口直接关闭则回滚(笔者在RHEL5下测试如此)

       DML语句执行失败则自动回滚

 

    提交或回滚前的数据状态

       改变前的数据状态是可以恢复的

       执行DML 操作的用户可以通过SELECT 语句查询之前的修正

       其他用户不能看到当前用户所做的改变,直到当前用户结束事务。

       DML语句所涉及到的行被锁定,其他用户不能操作

 

    提交后的数据状态

       数据的改变已经被保存到数据库中。

       改变前的数据已经丢失。

       所有用户可以看到结果。

       锁被释放,其他用户可以操作涉及到的数据。

       所有保存点被释放。

 

七、并发事务

    多个用户同时与数据库交互,且每个用户都可以同时访问自己的事物,这种事务称为并发事务

    对于同一个对象上运行的多个事务,仅当执行commit时才对彼此的查询产生影响

   

下表中演示了并发事务的处理:

 

Trans1

Trans2

T1

SQL> SELECT COUNT(1) FROM emp;

 

  COUNT(1)

----------

        16

SQL> SELECT COUNT(1) FROM scott.emp;

 

  COUNT(1)

----------

        16

T2

SQL> INSERT INTO emp(empno,ename,salary)

  2  SELECT 6666,'Jenney',3000 FROM DUAL;

 

T3

SQL> UPDATE emp

  2  SET salary = salary + 200 WHERE ename = 'SCOTT';

 

T4

SQL> SELECT COUNT(1) FROM emp;

 

  COUNT(1)

----------

        17

SQL> SELECT COUNT(1) FROM scott.emp;

 

  COUNT(1)

----------

        16

T5

SQL> COMMIT;

 

T6

 

SQL> SELECT COUNT(1) FROM scott.emp;

 

  COUNT(1)

----------

        17

 

    示例中显示了两个不同的事务交叉执行的顺序,可以看出,仅当事务执行COMMIT后,相关事务才产生影响

 

 

 

八、利用AUTOCOMMIT进行事务控制

    SET AUTOCOMMIT ON

   

    设置自动提交,每执行一条语句,就提交。将autocommit设成ON时,在进行DML操作时似乎很方便,

    但在实际应用中有时可能会出现问题,如,在有些应用中要同时对几个表进行操作,对于这些表建立

    了外键联系,如果一旦操作失败另一个表,就很麻烦了。

 

       关于锁及事物的隔离级别请关注后续文章


上一篇:yum介绍与仓库的配置


下一篇:一张图看懂互联网史上最大规模的公共云迁移案例