InnoDB---可重复读隔离级别的底层实现原理

本文解析了InnoDB存储引擎如何通过多版本并发控制(MVCC)和快照技术实现可重复读隔离级别。在这一级别下,事务能读取到已提交的新记录,但看不到其他事务对现有记录的更新,确保了数据的一致性和事务的隔离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

可重复读的实现

    Repeatable Read(可重复读):一个事务在执行过程中可以看到其他事务已经提交的新插入的记录(读已经提交的,其实是读早于本事务开始且已经提交的),但是不能看到其他事务对已有记录的更新(即晚于本事务开始的),并且,该事务不要求与其他事务是“可串行化”的。

    这句话的核心,是“但是不能看到其他事务对已有记录的更新”,那么RR隔离级别是怎么保证这一点的呢?

    使用MVCC(多版本并发控制)。InnoDB为每行记录添加了一个版本号(系统版本号),每当修改数据时,版本号加一。
在读取事务开始时,系统会给事务一个当前版本号,事务会读取版本号<=当前版本号的数据,这时就算另一个事务插入一个数据,并立马提交,新插入这条数据的版本号会比读取事务的版本号高,因此读取事务读的数据还是不会变。

    如果数据库并发控制引擎是单纯的封锁协议机制,则应该在读取数据的时候,判断数据项是不是其他事务更新过的。可是InnoDB没有这么做,而是通过如下方式,在RR隔离级别下为事务设置了一个“一致性读视图(即快照)”,之后读取数据,就是根据这个快照来获取,这样,就不能看到他晚于本事务的事务对已有记录的更新(更新生成新版本,必然不在旧的快照所限定的范围内)。

static my_bool snapshot_handlerton(THD *thd, plugin_ref plugin, void *arg)

{

    handlerton *hton= plugin_data<handlerton*>(plugin);

    if (hton->state == SHOW_OPTION_YES && hton->start_consistent_snapshot) //隔离级别是RR时start_consistent_snapshot才被赋值

    {

        hton->start_consistent_snapshot(hton, thd); //对于InnoDB,实际执行innobase_start_trx_and_assign_read_view()函数

        *((bool *)arg)= false;

    }

    return FALSE;

}

    如图11-4和下面的代码分析,在事务开始的时候trans_begin()会调用snapshot_handlerton()函数指针即使用innobase_start_trx_and_assign_read_view()函数在可重复读隔离级别下创建一个快照,其他隔离级别则不创建快照。

 

 

图11-4 snapshot_handlerton()函数上下文调用关系图

innobase_start_trx_and_assign_read_view(  //在可重复读隔离级别下创建一个快照,其他隔离级别则不创建快照

    handlerton*    hton,    /*!< in: InnoDB handlerton */

    THD*           thd)     /*!< in: MySQL thread handle of the user for whom the transaction should be committed */

{...

    if (trx->isolation_level == TRX_ISO_REPEATABLE_READ) { //如果是RR隔离级别,则给read view赋值,即构建一致性视图

        trx_assign_read_view(trx);  //为读一致性视图(快照)赋一个值,注意在store_lock()中应隔离级别小于RR才关闭快照

    } else {

        push_warning_printf(thd, Sql_condition::SL_WARNING,

                    HA_ERR_UNSUPPORTED,

                    "InnoDB: WITH CONSISTENT SNAPSHOT"

                    " was ignored because this phrase"

                    " can only be used with"

                    " REPEATABLE READ isolation level.");

    }

...

}

    之后,在每条SQL语句执行的时候,根据隔离级别判断是不是要使用一个新的快照,如果是可重复读,则不使用新快照,沿用老的快照,这样就能保证所有的读操作看到的是同一个数据状态;同时也确保了读已提交隔离级别下一个事务块内的不同语句的读操作看到的不是同一个数据状态。

ha_innobase::store_lock(...)

{...

    if (lock_type != TL_IGNORE && trx->n_mysql_tables_in_use == 0) {

        trx->isolation_level = innobase_map_isolation_level((enum_tx_isolation) thd_tx_isolation(thd));

        if (trx->isolation_level <= TRX_ISO_READ_COMMITTED  //隔离级别小于等于读已提交,关闭老的快照。可重复读不关闭老快照所以可以沿用

            && MVCC::is_view_active(trx->read_view)) {

            /* At low transaction isolation levels we let each consistent read set its own snapshot */

            mutex_enter(&trx_sys->mutex);

            trx_sys->mvcc->view_close(trx->read_view, true);  //隔离级别小,关闭快照,这样下一条SQL执行时,将获取新快照

            mutex_exit(&trx_sys->mutex);

        }

    }

...

}

    从上面的分析可以看出,InnoDB的可重复读的实现,利用了实现MVCC技术的快照技术。这是MVCC和基于封锁技术这两个并非控制技术的结合之处

<think>好的,我需要回答用户关于事务隔离级别底层实现原理的问题。首先,我需要回忆数据库事务隔离的基本概念和四种隔离级别未提交、已提交、可重复和串行化。接下来,要理解每个隔离级别解决的问题,比如脏、不可重复和幻。 根据用户提供的引用内容,特别是引用[1]到[4],这些引用提到了MySQL的事务隔离级别、可串行化的实现方式以及锁机制。需要整合这些信息,说明不同隔离级别实现机制,比如MVCC(多版本并发控制)和锁的应用。 首先,未提交可能不使用锁,直接取最新数据,但会有脏的问题。已提交可能通过MVCC,每个查询生成快照,或者使用行锁。可重复可能使用事务级别的快照,避免不可重复。而串行化则通过锁机制,确保事务串行执行。 需要区分不同数据库的实现,比如MySQL的InnoDB引擎在可重复级别下如何通过MVCC和间隙锁来防止幻。同时,要提到每个隔离级别的性能权衡,比如串行化虽然安全但性能差。 用户的问题还要求生成相关问题,我需要围绕事务隔离的实现机制、不同级别的区别、性能影响和应用场景来提问。例如,关于MVCC的工作原理,或者如何选择隔离级别。 要确保回答结构清晰,分点说明每个隔离级别实现原理,并引用提供的资料。注意使用中文,正确应用LaTeX格式,比如锁的机制用行内公式,如$X锁$。同时,独立公式可能需要举例,比如事务版本号的生成,但如果没有必要,可以不用添加。 最后,检查是否遗漏了引用内容,特别是关于可串行化使用加锁的方式,以及不同隔离级别在性能上的影响。确保回答正确,符合用户的要求。</think>### 事务隔离级别底层实现原理 事务隔离级别实现依赖于数据库的并发控制机制,主要包括**锁机制**和**多版本并发控制(MVCC)**。以下分四个隔离级别详细说明其底层原理--- #### 1. 未提交(Read Uncommitted) - **实现原理**:直接取内存中最新数据,**不进行任何并发控制**,允许取其他未提交事务的中间状态。 - **问题**:可能到脏数据(脏)[^1]。 - **示例**:事务A修改数据但未提交,事务B直接取修改后的值。 --- #### 2. 已提交(Read Committed) - **实现原理**: - **锁机制**:通过短期的行级锁(如$S锁$)阻止其他事务修改当前事务正在取的数据,但取后立即释放锁[^3]。 - **MVCC**:为每个查询生成独立的快照(基于事务版本号),仅取已提交的数据。 - **示例**: ```sql -- 事务A取数据时生成快照,事务B提交后,事务A再次取会看到新数据 ``` --- #### 3. 可重复(Repeatable Read) - **实现原理**: - **MVCC**:事务启动时生成全局快照,后续所有操作基于此快照,避免不可重复- **间隙锁(Gap Lock)**:在InnoDB中,通过锁住索引记录的间隙(如$[5,10]$区间)防止幻- **示例**: ```sql -- 事务A查询age>20的记录时,间隙锁阻止其他事务插入age=25的新数据 ``` --- #### 4. 串行化(Serializable) - **实现原理**: - **严格锁机制**:所有操作加$S锁$,写操作加$X锁$,锁持续到事务结束,强制事务串行执行[^3][^4]。 - **无MVCC**:直接通过锁实现最高隔离级别,完全避免并发问题。 - **性能代价**:高并发场景下吞吐量显著下降。 --- ### 核心技术对比 | 机制 | 适用隔离级别 | 特点 | 性能影响 | |------------|--------------------|--------------------------------|------------------| | 行级锁 | 已提交、串行化 | 短锁减少冲突,长锁确保一致性 | 中等至高 | | 间隙锁 | 可重复(MySQL) | 防止幻 | 额外锁开销 | | MVCC | 已提交、可重复 | 无锁,通过版本链回溯历史数据 | 低至中等 | --- ### 关键实现细节 1. **版本链与回滚段** MVCC通过为每行数据维护多个版本(通过$trx\_id$标记事务版本),结合回滚段(Undo Log)回溯历史状态。 2. **快照生成规则** 可重复隔离级别下,快照的可见性由事务启动时的活跃事务列表决定,公式: $$ \text{可见条件:} \ trx\_id \leq \text{当前事务ID} \ \land \ trx\_id \notin \text{活跃事务列表} $$ 3. **锁的兼容性** - $S锁$(共享锁)与$X锁$(排他锁)互斥 - 间隙锁与插入意向锁互斥 --- ### 性能与场景权衡 - **低隔离级别(如已提交)**:适合高并发场景(如资讯平台),通过MVCC避免锁竞争[^2]。 - **高隔离级别(如串行化)**:用于金融交易、库存管理等强一致性场景,通过锁保证安全[^2]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值