事务

来源:互联网 发布:cn域名续费多少钱 编辑:程序博客网 时间:2024/05/17 23:51

1、事务的概念

      事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。

      事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。

      事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。


      例如:在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。


2、事务的特性

      事务是恢复和并发控制的基本单位。

      事务的4个特性(ACID):原子性、一致性、隔离性、持久性。

      原子性(atomicity):一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。

      一致性(consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

      隔离性(isolation):一个事务的执行不能被其它事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

      持久性(durability):持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其有任何影响。


3、事务并发的问题

      一个数据库可能拥有多个访问客户端,这些客户端都可以并发方式访问数据库。数据库中的相同数据可能同时被多个事务访问,如果没有采取必要的隔离措施,就会导致各种并发问题,破坏数据的完整性。


      a:脏读(dirty read)

            脏读又称无效数据读出。一个事物读取另外一个事务还没有提交的数据叫脏读。

            例如:事务T1修改了一行数据,但是还没有提交,这时候事务T2读取了被事务T1修改后的数据,之后事务T1因为某种原因Rollback了,那么事务T2读取的数据就是脏读


            解决办法:把数据库的事务隔离级别调整到READ-COMMITED


      b:不可重复读(unrepeatable read)

            不可重复读是指在同一个事务内,两个相同的查询返回了不同的结果。

            例如:事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。


            解决办法:把数据库的事务隔离级别调整到 REPEATABLE_READ


      c:幻读(phantom read)

            幻读是指T1事务读取T2事务提交的新增数据,这时T1事务将出现幻读的问题。

            幻读一般发生在计算统计数据的事务中。例如:假设银行系统在同一个事务中,两个统计存款账户的总金额,在两次统计过程中,刚好新增了一个存款账户,并存入100元,这时,两次统计的总金额将不一致。

            如果新增的数据刚好满足事务的查询条件,这个新数据就进入了事务的视野,因而产生了两个统计不一致的情况。


            解决办法:把数据库的事务隔离级别调整到 SERIALIZABLE_READ


      ☆☆☆:幻读和不可重复读是两个容易混淆的概念,幻读是指读到了其它已经提交事务的新增数据,而不可重复读是指读到了已经提交事务的更改数据(更改或删除)。为了避免这两种情况,采取的对策是不同的,防止读取到更改数据,只需要对操作的数据添加行级锁,阻止操作中的数据发生变化;而防止读取到新增数据,则往往需要添加表级锁--将整个表锁定,防止新增数据。


      ☆☆☆:脏读、不可重复读、幻读的级别高低是:脏读 < 不可重复读 < 幻读。所以,设置了最高级别的SERIALIZABLE_READ就不用再设置REPEATABLE_READ和READ_COMMITTED


      d:丢失更新(lost update):

            事务T1读取了数据,并执行了一些操作,然后更新数据。事务T2也做相同的事,则T1和T2更新数据时可能会覆盖对方的更新,从而引起错误。

            d1:第一类丢失更新

            A事务撤销时,把已经提交的B事务的更新数据覆盖了。这种错误可能造成很严重的问题,通过下面的账户取款转账就可以看出来:

      A事务在撤销时,“不小心”将B事务已经转入账户的金额给抹去了。


            d2:第二类丢失更新

            A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失:

            

            上面的例子里由于支票转账事务覆盖了取款事务对存款余额所做的更新,导致银行最后损失了100元,相反如果转账事务先提交,那么用户账户将损失100元。


4、事务隔离级别

      a:未授权读取

            也称为读未提交(read uncommitted):允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其它事务读取此行数据。该隔离级别可以通过“排他写锁”实现。

      b:授权读取

            也称为读提交(read commited):允许不可重复读取,但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其它事务继续访问该行数据,但是未提交的写事务将会禁止其它事务访问该行。

      c:可重复读

            可重复读取(repeatable read):禁止不可重复读和脏读取,但是有时可能出现幻读数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其它事务。

      d:序列化

            序列化(serializable):提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。仅仅通过“行级锁”是无法实现事务序列化的,必须通过其它机制保证新插入的数据不会被刚执行查询操作的事务访问到。


      ☆:在相同的数据环境下,使用相同的输入,执行相同的工作,根据不同的隔离级别,可以导致不同的结果。不同事务隔离级别能够解决的数据并发问题的能力是不同的。隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为read commited。它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

      事务的隔离级别和数据库并发性是对立的,两者此消彼长。一般来说,read uncommitted隔离级别的数据库拥有最高的并发性和吞吐量,而使用Serializable隔离级别的数据库并发性最低。


     

      






0 0