天天看點

InnoDB---序列化隔離級别的實作

序列化的實作

    InnoDB對于序列化的實作方式,是通過兩種方式實作的。

    第一種,當SELECT語句在一個顯式的事務塊内,如執行表11-9中的編号為1的情況,将施加LOCK_S鎖,根據表11-6(記錄鎖事務鎖相容表)可知,LOCK_S鎖排斥寫鎖,是以序列化隔離級别下隻允許并發地讀取操作,并發寫被禁止,是以實作了可序列化(參見1.2.2節)。相應代碼如下:

ha_innobase::

external_lock

(...)

{...

    if (lock_type != F_UNLCK) {

...

        if (trx->isolation_level ==

TRX_ISO_SERIALIZABLE

  //

序列化隔離級别

            && m_prebuilt->select_lock_type == LOCK_NONE

            && thd_test_options(thd,

OPTION_NOT_AUTOCOMMIT

|

OPTION_BEGIN

)) { //

且在一個顯式事務塊内部

            m_prebuilt->

select_lock_type

=

LOCK_S

;  //

加讀鎖,即 'LOCK IN SHARE MODE'

            m_prebuilt->stored_select_lock_type = LOCK_S;

        }  //

否則,不加鎖(這一點也很重要)

...

    } else {

        TrxInInnoDB::end_stmt(trx);

        DEBUG_SYNC_C("ha_innobase_end_statement");

    }

...}

    第二種,當SELECT語句不在一個顯式的事務塊内,則通過擷取最新快照(在事務開始的時候,),然後讀取資料。此時,因基于快照的一緻性讀不需要加鎖,是以其加鎖情況對應到了表11-9中的編号2對應的情況。

表11-9 序列化隔離級别加鎖情況

隔離級别 編号 SQL 語句 施加的鎖
SERIALIZABLE 1 BEGIN; S0; LOCK_S + LOCK_REC_NOT_GAP
2 S0; 沒有鎖

說明:

q  S0:SELECT * FROM bluesea WHERE c1=2;   //使用主鍵索引做WHERE條件

    另外,對于FLUSH...WITH READ LOCK語句,序列化隔離級别下也需要加讀鎖LOCK_S,代碼如下:

ha_innobase::

store_lock

(

...

        if (trx->isolation_level ==

TRX_ISO_SERIALIZABLE

) {

                m_prebuilt->select_lock_type =

LOCK_S

;

                m_prebuilt->stored_select_lock_type =

LOCK_S

;

        } else {

                m_prebuilt->select_lock_type = LOCK_NONE;

                m_prebuilt->stored_select_lock_type = LOCK_NONE;

        }    

...

}                      

    與序列化相關的,還有innobase_query_caching_of_table_permitted()函數,序列化隔離級别不允許緩沖查詢。