zoukankan      html  css  js  c++  java
  • 事务属性小结

    在NoSql和内存数据库如此流行的今天,在谈关系型数据库的貌似有点落伍了,不过在传统软件行业和对数据一致性和安全性要求比较高的行业,关系型数据库还是比较普遍的。正好最近看到一个数据库事务相关的知识,自己在这几年的工作中用的比较多,也在事务上面犯过很多的错误,正好借这个机会整理以下。

     

    事务的ACID属性

    A(Atomicity)原子性: 在一个事务上下文里面,对数据库进行的任何操作,必须保证是原子的,也就是说要么不做,要么全部都做,不能只做一部分。比如insert一条数据和delete一条数据,不知能只做insert操作而不做delete操作

     

    C(Consistency)一致性:在事务的处理过程中,数据库必须时刻要避免被置于不一致 (inconsistent)的状态。这意味着在事务期间,每次对数据库实施的插入、更新或删除操作 时,数据库的完整性约束(integrity constraints)都要得到保证,即使在事务还未被提交时 也必须如此。比如非空约束。

     

    I(Isolation)隔离性:两个不同的事务相互之间是彼此隔离程度。有一种说法是事务之间是彼此隔离的,一个事务不能够读取另一个事务未提交的数据,这个不太准确,这个属于事务的隔离级别。wiki上的解释是“

    The isolation property ensures that the concurrent execution of transactions results in a system state that could have been obtained if transactions are executed serially, i.e. one after the other“

     

    D(Durability)持久性:事务一旦提交,在事务中对数据库进行的修改也就进行持久化存储了,不会由于系统故障导致提交后的数据丢失。

     

    ACID是关系型数据库最重要的特性。

     

    事务的隔离级别

    这个和ACID中的隔离性有关,主要分为四个级别

    1.         读未提交(Read UnCommited)

    这个是最弱的隔离级别,不满足ACID中的隔离性的要求,大多数数据库并不提供这个支持。见下面的例子:

     1

    由于事务B读取了事务未提交的数据,一旦回滚,事务B读取的数据就是有问题的。

     

    2.         读已提交(Read Commited)

    这个级别不允许事务B读取事务A还未提交的 update操作更新后的数据,但是对于事务A的insert操作,在未提交之前,对事务B还是可见的。这就可能出现幻读。见下面的例子

     2 1

     

    这里面不会出现脏读,保证事务B读取的都是事务A update提交之后的数据。但是对于insert操作,就可能存在脏读的问题,例如下面一个例子

     2 2

    数据库里面存在ABC这一条记录,事务A新增加了XYZ这一条记录,如果事务A正常提交,事务B读取的结果没有问题,如果事务A回滚,那么事务B就出现的脏读,多了XYZ这一条记录。

     

    记得曾经自己在这个上面弄了一个bug,大概的业务逻辑是:先根据批日期,查询某一天的总数据量,然后在查询明细数据,生成到文件里面,然后更新状态,这些都在一个事务里面。事务的隔离级别是默认的。当初发现查询的总数据量和生成的明细数据数据不一致,原来在事务里面,还会有其他的事务往表里面插入数据,无论是否最终提交,都会被查询出来,生成到文件里面。

     

      

    3.         可重复读(Repeatable Read)

    这个隔离级别对于insert的数据提交之后才对另外一个事务可见,不会存在幻读的情况。

    3 1

    但是事务之间还是会存在互相影响的情况,见下面的例子

     3 2

    事务A和事务B都是先读取Price的价格,然后在价格上面减去一定的数值,我们期望结果是70,但是实际结果可能是90,也可能是80。

     

    4.         可序列化

    事务只能顺序的读取数据,当一个事务在读取和修改数据的时候,另外一个事务只能挂起,直到正在读取和修改数据的事务提交之后,挂起的事务才能执行。

    4

     

     

     

    事务的隔离级别与并发性,一致性之间存在关系,隔离级别越高,并发性就越低,一致性就越高

     

    这几种隔离级别并不是每个数据库都会提供,oracle没有提供第一种隔离级别“读未提交数据”,一般情况下,大多数数据库的默认隔离级别就是“读提交数据”。

    这些隔离级别都是定义在java.sql. Connection中,在获取连接的时候我们可以进行设置,但是一般情况下,系统会用数据库默认的级别来设置。

     

    Connection.TRANSACTION_READ_UNCOMMITTED;

    Connection.TRANSACTION_READ_COMMITTED;

    Connection.TRANSACTION_REPEATABLE_READ;  

    Connection.TRANSACTION_SERIALIZABLE;

     

    声明式编程中事务的属性

    我们在使用spring活着ejb声明式编程的时候,还会接触到事务的传播属性,在spring的 TransactionDefinition 类里面进行定义。具体有以下几个数值

     

    Required(需要)

    Mandatory(强制必须)

    RequiresNew(需要新的)

    Supports(支持)

    NotSupported(不支持)

    Never(不用)

     

     

    Required:当前方法必须要求开启事务,如果当前线程不存在事务,则开启新的事务,如果当前线程已经存在事务,就加入到当前事务。这个是经常使用的。但是要注意的就是一旦事务中某一个方法回滚,当前事务上下文里面所有的操作都回滚,考虑到下面一个例子:

    methodA{  

        read A =100  ;    

    If(methodB()){

           A = A + 1;  

    }else{

       A = A - 1;  

    }

    Update A;

    Commit;

    }

     

     

    methodB{

      read B ;

      B = B – 1

      Update B;

     

      If(B>0){

    Commit;

    Return ture;

      }else{

         Rollback

    Return false;

      }

    }

     

     

    假设A和B的事务都是Required,那么当调用MethodA的时候,如果method回滚了,对A的修改也就回滚了。所以上面的代码不会达到预期的结果,也就是说A不可能修改成为99。

     

     

    Required New:当前方法必须要求开启新的事务,如果当前线程已经存在事务上下文,就暂停当前事务,等到新事务结束之后,在继续恢复之前的事务。就拿上面的例子来说,methodB的对事务的修改不会影响到methodA。两个事务之间不会互相影响。经常可以用到的场景就是在业务发生异常的时候发送短消息。如果业务发生异常,业务回滚,但是由于发送段消息是新的事务,不会受到业务异常的影响。

     

    Mondary:当前方法必须要求事务,如果当前线程不存在事务,就抛出异常,如果存在,就加入到事务里。

     

     

    Support:当前方法支持事务,如果当前线程存在事务,就加入到事务中去,如果不存在,不做任何操作。

     

    Not Support:当前方法不支持事务,如果当前线程存在事务,就挂起当前事务,执行完当前方法,恢复事务。一般情况下在查询的时候使用,如果一个方法只是查询,并且非常耗时,就可以使用Not Support,避免事务时间超长。

     

    Never:当前方法不支持事务,如果当前线程存在事务,则抛出异常。这种用的比较少。

     

     

  • 相关阅读:
    Python编程第5讲—if 语句
    GIT 笔记
    jQuery多余文字折叠效果
    静态库与动态库的制作与使用
    Makefile
    C++ 有理数类
    使用mstest.exe 命令行跑test case(不安装Visual Studio 2010)
    Termp Folder and its subfolders
    ToString() 格式化字符串总结
    REST基础
  • 原文地址:https://www.cnblogs.com/aigongsi/p/2716086.html
Copyright © 2011-2022 走看看