zoukankan      html  css  js  c++  java
  • 事务并发控制

    前段是时间涉及到数据库的隔离级别问题,在网上搜索一下,发现大部分都说的模棱两可,而且也有很多错误。于是查阅了上学时的课本《数据库系统概论》 和JDBC的文档。现在把总结的结果记录下来,供大家分享.
    1. DBMS事务并发控制     

    1.1 事务并发操作的问题         DMBS允许东西运行多个事务,这些事务可能同时操作同一数据对象。这可能造成以下问题        丢失修改 : 一个事务的修改被另一个事务覆盖。        不可重复读 : 在一个事务中执行相同的查询,两个的结果不一样。        幻读 : 幻读是不可重复多的一种,在一个事务中执行相同的查询,第二次的结果行比第一次少或者多(行被delete或者被insert)        脏读 : 一个事务读到的数据无效的,是另外一个事务回滚的数据
           所以需要对事务进行并发控制,采用的主要技术是锁。
        

    1.2 锁        

      锁是指一个事务对每个数据对象进行操作时,需要对数据对象加对应锁。这样其他事务最此数据对象访问就受限。当操作结束后事务释放此锁。        

      1.2.1 锁的粒度          

      锁的粒度包括逻辑单元也可以是逻辑单元:         

       列值(注意不是列)、列值集合、行、表、索引项、整个索引、数据库;         

      也可以是物理单元:         

      数据页、索引页、块。         

      事务可以对各种类型的数据对象加锁,即多粒度加锁。这样在DBMS中就存在了可以被加锁的数据对象树,简称多粒度树。如下,三级多粒度树。  
           1.2.2 锁的类型          

      锁分为5中类型,如下          排他锁(X锁):                也叫写锁。若事务T对数据对象A添加X锁,则只允许T读取和修改A,其他任何事务都不能再对A添加任何类型的锁,直到T释放此锁。          共享锁(S锁):                也叫读锁。若事务T对数据对象A添加此类型锁,则事务T允许读取A但不允许修改A,其他事务只能再对A添加S锁,而不能加X锁,直到A上的所有S锁都被释放。          意向排他锁(IX锁):                如果对一个数据对象加IX锁,表示他在多粒度树中的后裔(包括直接孩子,孩子的孩子等等所有的后面的结点)有被加X锁的可能(意向)。          意向共享锁(IS锁):                如果对一个数据对象加IS锁,表示他在多粒度树中的后裔(包括直接孩子,孩子的孩子等等所有的后面的结点)有被加S锁的可能(意向)。          共享意向排他锁(SIX):                如果对一个数据对象加SIX锁,则表示对他加S锁,再加IX锁。
             这个5类锁的相容矩阵如下, T1已经对数据对象加锁,T2尝试对数据对象加锁。Y表示成功,N表示失败。  
             在Oracle中上面五个类型的锁分别对应X锁、S锁、RX锁、RS锁、SRX锁,而且加锁粒度包括行级和表级,不包括数据库。
            1.2.3锁协议          

      对数据对象加锁时,需要约定一些规则,例如合适申请、持锁时间、何时释放。这些规则称为锁协议。DBMS遵循哪些协议要看具体情况。下面介绍一些协议:          基本锁协议:当事务T对数据对象A加锁时,如果A上已经存在锁且和T欲加锁不相容, 那么T对待,直到A上存在的所被释放。          一级锁协议:事务T在修改数据对象A之前必须先对其加X锁,知道事务结束才释放。          二级锁协议:在一级锁协议的基础上加上事务T在读取数据对象A之前必须先对其加S锁,读完后即可释放S锁。          三级锁协议:在一级锁协议的基础上加上事务T在读取数据对象A之前必须先对其加S锁,直到事务结束才释放。          多粒度锁协议: 多粒度树中的每个结点被独立地加锁(显式锁)。对一个结点加锁意味着其所有后裔结点也被加以同样类型的锁(隐式锁, 并没有真正在后裔结点加锁,只是在逻辑上后裔结点具有同样类型的锁,所以叫隐式锁。)。显式锁和隐式锁的效果是一样的,因此检查锁相容时不仅要检查显式锁还要检查隐式锁。所以事务T要对数据对象A加锁,需要检查其祖先(包括直接的和间接的所有上层结点)上的显式锁(检查A的隐式锁是否与欲加的显式锁不相容)、检查其显式锁(检查A已存在的显式锁是否与欲加的显式锁不相容)、检查其后裔的显式锁(检查欲加给后裔的隐式锁是否与后裔已存在的显式锁不相容),如果发现一个不相容锁,则T等待。          意向锁协议:对任一结点加锁时,必须先对其祖先(包括直接的和间接的所有上层结点)加意向锁,顺序为自上而下。释放结点上锁后,释放其祖先上的意向锁,释放顺序为自下而上。意向锁的含义是如果对一个结点加意向锁,则说明该结点的后裔结点正在被加锁。所以事务T要对数据对象A加锁,需要检查A祖先上的所有锁(检查祖先上的锁是否与欲加给祖先的意向锁相容)、检查A上的所有锁(检查A上的锁是否与欲加他的锁相容),如果发现一个不相容锁,则T等待。                   多粒度锁协议,在给结点加锁时需要递归检查子结点的显式锁,当子结点很多时,将带来很多的性能开销。意向锁是针对这个问题进行的改进,他将锁在多粒度树间的传递由原来的由上而下变成由下而上,从而提高了性能。Oracle采用了意向锁协议。
    2.DBMS事务隔离级别     

      2.1 事务隔离级别的说明         上一节讨论的内容是DBMS实现事务并发控制的内容,是DBMS内部问题。那么如何从外面干预DBMS内部的事务并发控制呢?         当事务写数据对象时,DBMS使用X锁及其相关锁(例如IX)进行操作,这个过程是固定的,外界无法也无需干预。        当事务读数据对象时,哪些数据对象应该对此事务可见呢?例如,其他事务已写还未提交的、其他事务已写已提交的,等等。这个应该是可以选择的,也就是 说外界可以干预。DBMS通过事务隔离级别来让事务选择读哪些数据对象。        可以这样理解,写是严格操作,不允许发生错误,所以其并发控制是最严格的,也是不可选的。而读是宽松的操作,允许出现 不可重复读 、幻读、脏读问题,所以其并发控制是分多个级别的,可以选择相应的级别改变并发度和允许出现的错误。
        2.2 事务隔离级别类型          ANSI/ISO SQ92标准定义了如下事务隔离级别:          2.2.1未提交读(read uncommitted)            事务可以读其他事务未提交数据对象。            潜在问题: 脏读、不可重复读、幻读            DBMS锁操作 :不加任何锁,直接读任意数据对象。         2.2.2提交读(read committed)            事务可以读其他事务已提交数据对象,读完后此数据对象可以被其他事务再读写。            可能出现的问题: 不可重复读、幻读            DBMS锁操作(采用意向锁协议) :加S锁,祖先加IS锁,读完后立即释放S锁和祖先的IS锁。         2.2.3 重复读(repeatabe read) :             事务可以读其他事务已提交数据对象,读完后此数据对象不可以被其他事务再写但可以读,直到 此事务结束。            可能出现的问题: 幻读            DBMS锁操作 (采用意向锁协议):加S锁,祖先加IS锁。事务结束后释放S锁和祖先的IS锁。         2.2.4 序列化(seriaizabe):            事务读之前,其他事务已提交的数据对象对此事务可见,读完后整个多粒度树只读不能写,直到事务结束。所以他严重的降低了事务的并发度,特别是多粒度树很深时,这也是Oracle没有将数据库作为多粒度树根的原因。在此级别下事务完全隔离,就如所有的事务都顺序执行一样。             可能出现的问题: 无            DBMS锁操作 (采用意向锁协议):加S锁,祖先加SIX锁,事务结束后释放S锁和祖先的SIX锁。
        2.3 隔离级别的使用           隔离级别是针对事务的。但是也可以配置Session(对应JDBC的Connection)默认的和DBMS全局默认的事务隔离级别。这样创建事务时不指定就采用默认的事务隔离级别。
    3. JDBC事务     在JDBC中通过Connection执行事务。一个Connection可以执行多个事务。一个事务可以执行多个SQL语句。
       3.1 事务的开启     在Connection中,如果不存在事务,那么在执行SQL语句之前自动开启一个事务。如果事务已经存在那么直接使用其执行SQL语句。
       3.2 事务的结束     SQL语句完成之后调用Connection的commit或者rollback方法结束当前事务。在执行之后的SQL语句之前自动开启一个新的事务。
       3.3 设置事务的隔离级别     在JDBC中不能单独设置事务的隔离级别,只能通过Session(对应Connection)间接设置,通过Connection的setTransactionIsolation方法。调用此方法之后,如果存在当前事务并且改变了Connection的事务隔离级别那么会引起当前事务立刻提交,之后开启的事务将采用此事务隔离级别。
       3.4 SQL语句的完成时间     SQL语句的类型不同,其SQL语句完成时间不同。具体如下    DML, DDL语句:SQL语句执行完成,那么SQL语句就算完成。    Select语句:查询语句执行完成后返回ResultSet,当调用ResultSet的close方法后SQL语句算完成。    多结果语句:当SQL语句返回多结果时(例如执行存储过程,批处理),那么SQL语句的完成时间是所以结果的最大者。
       3.5Connection的自动提交模式     Connection有个模式叫自动提交,在这种模式下SQL完成后立即调用Connection的commit方法或者rollback方法。这就使每个SQL在独立的事务中执行。自动提交模式模式是开启的。

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    平衡二叉树之RB树
    平衡二叉树之AVL树
    实现哈希表
    LeetCode Median of Two Sorted Arrays
    LeetCode Minimum Window Substring
    LeetCode Interleaving String
    LeetCode Regular Expression Matching
    PAT 1087 All Roads Lead to Rome
    PAT 1086 Tree Traversals Again
    LeetCode Longest Palindromic Substring
  • 原文地址:https://www.cnblogs.com/wzhanke/p/4618434.html
Copyright © 2011-2022 走看看