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在独立的事务中执行。自动提交模式模式是开启的。

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

  • 相关阅读:
    基于Token的身份验证--JWT
    在eclipse中使用maven创建springMVC项目
    Mybatis框架插件PageHelper的使用
    java 中==符号的坑
    Gradle project sync failed.
    intellij idea android错误: Missing styles. Is the correct theme chosen for this layout?
    thinkpad win8.1 无线连接受限
    struts2
    在Strust2 使用datatimepicker 标签引发的一系列问题
    struts2中css,js等资源无效 非路径问题(新手问题)
  • 原文地址:https://www.cnblogs.com/wzhanke/p/4618434.html
Copyright © 2011-2022 走看看