并发控制

并发操作带来的数据不一致性有

  • 丢失修改

    两个事务读入同一数据

  • 不可重复读

    2次读取未用数据,前后不一致(为了检验)

  • 读“脏”数据

    事务A修改数据并写会DB后,事务B读取,事务A因某些原因回滚,事务B此时没意识到,则读取了“脏”数据

封锁协议

  • 一级锁协议

    事务T在修改数据R之前加X锁,直到事务结束,防止丢失修改

  • 二级锁协议

    一级锁协议基础上,事务T在读取数据R之前先加S锁,读完即可释放防止读脏数据

  • 三级锁协议

    一级锁协议基础上,事务T在读取数据R之前先对其加S锁,直到事务结束才释放防止不可重复读

隔离级别

  1. 读不提交(Read Uncommited, RU)

    事务不隔离,可能产生脏读,可以读取未提交记录,实际中不会使用

  2. 读提交(Read Commited, RC)

    仅读已提交数据,但可能产生不可重复读与幻读,因为在此隔离机制下,每条语句都会读取到已提交事务的更新,若两次查询之间有其他事务提交,将会导致查询结果不同,对于insert也无法保证,但这种隔离机制使用还是比较广泛的

  3. 可重复读(Repeatable Read, RR)

    限定了其他事务对当前事务的删改,从而保证反复读取同一条记录不会发生变动,但未禁止增操作,会发生幻读

  4. 串行化(Serializable)

    消除幻读、不可重复读、脏读,但是并发度下降

幻读与不可重复读的区别

两者都表现为两次读取的结果不一致。

首先,抓住重点,不可重复读重点在于update和delete,而幻读的重点在于insert

如果使用锁机制来实现这两种隔离级别,在可重复读中,该sql第一次读取到数据后,就将这些数据加锁,其它事务无法修改这些数据(只是这些),就可以实现可重复 读了。但这种方法却无法锁住insert的数据所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会 发现莫名其妙多了一条之前没有的数据,这就是幻读,不能通过行锁来避免!!!

死锁的诊断

超时法、等待图法(有环)

可串行化调度

类似java的指令重排序,在单线程里面指令重排但是结果一致,而此相当于对并发事务重排

两端锁协议

为了保证数据库的可串行化,在对数据进行读、写前,要申请并获得对该数据的封锁,但此时不能释放锁(扩展阶段);在释放一个封锁之后,事务不在申请和获得任何其他封锁(收缩阶段)

封锁的粒度

粒度越大,封锁的数据单元越少,并发度越小,系统开销也越小;反之则反

  • 显式封锁

    直接将锁加到数据对象上

  • 隐式封锁

    数据对象没有被独立加锁,而是其上级节点解锁而使该数据对象加上锁

一般地,对某个对象加锁,系统要检查数据对象上的显式锁有无冲突再检查隐式锁,还要检查下级节点的显式加锁是否与本事务的隐式加锁冲突,效率低。因而有了意向锁,系统则无需检查下一节点的显式加锁

意向锁

含义:如果对一个节点加意向锁,说明该节点的下层节点正在被加锁;对任一节点加锁时,必须先对它的上层节点加意向锁

分为3种:

  • IS

    若对一个数据对象加IS锁,表示它的后裔节点准备加S锁

  • IX

    若对一个数据对象加IX锁,表示它的后裔节点准备加X锁

  • SIX

    若对一个数据对象加SIX锁,表示对它加S锁,再加IX锁

意向锁兼容矩阵:(+表示兼容,-表示不兼容)

/ IS IX S X
IS + + + -
IX + + - -
S + - + -
X - - - -
  • S、X、IS、IX锁兼容性矩阵为什么是这样子呢?
  1. 意向锁之间彼此不会冲突,因为它们都只是“有意”,而不是真干,所以是可以兼容的。在加行锁之前,会使用意向锁判断是否冲突
  2. IX和X的关系等同于X和X之间的关系,为什么呢?因为事务获得了IX锁,接下来就有权利获取X锁,这样就会出现两个事务都获取X锁的情况,这和我们已知的X锁和X锁之间互斥是矛盾的;
  3. S和IS、X和IS、IX和IS也可以由此推导出来。

你可能感兴趣的:(并发控制)