数据库事务?阿里巴巴面试必问的高频话题!

软件求生 2024-02-26 09:46:52

大家好,我是小米!今天我们来聊聊数据库事务,这可是面试中经常被问到的热门话题哦!数据库事务是我们在日常开发中经常接触到的概念,它保证了数据库操作的一致性和可靠性。那么,事务到底是什么呢?让我们一起来探讨吧!

事务的四大特性

在开始深入了解数据库事务之前,我们先来了解一下事务的四大特性:

原子性(Atomicity):原子性保证了事务的不可分割性,即事务中的操作要么全部执行成功,要么全部执行失败。这意味着如果事务中的任何一个操作失败,那么整个事务都会被回滚到事务开始之前的状态,保持数据的一致性。举个例子,假设一个银行转账操作包含从一个账户扣款和向另一个账户存款两个步骤,如果在扣

一致性(Consistency):一致性确保了事务的执行不会破坏数据库的完整性约束,即事务执行前后,数据库从一个一致性状态转换到另一个一致性状态。换句话说,即使在多个事务并发执行的情况下,数据库也始终保持着一致的状态。例如,在数据库中执行的所有转账操作总金额应该保持不变,以确保数据库的一致性。

隔离性(Isolation):隔离性是指多个事务并发执行时,每个事务都应该感觉不到其他事务的存在,即每个事务都应该感觉自己是在独立执行的。这意味着事务之间的操作应该是相互隔离的,不应该相互干扰。例如,在一个并发环境中,如果两个事务同时对同一数据进行读取和修改操作,数据库系统应该能够保证这两个操作是相互独立的,不会相互影响。

持久性(Durability):持久性确保了事务一旦提交,其结果就是永久性的,即使系统崩溃也不会丢失。这意味着一旦事务提交成功,所做的修改就会永久保存在数据库中,即使在系统发生故障或崩溃的情况下,数据也不会丢失。为了实现持久性,数据库系统通常会使用日志来记录事务的操作,以便在系统崩溃后可以通过日志来恢复数据。

MySQL如何实现四个特性

那么,MySQL又是如何实现这四个特性的呢?接下来我们一一来看。

原子性:MySQL使用redo log(重做日志)来实现原子性,记录事务所做的修改,保证事务的完全提交或者完全回滚。

一致性:MySQL通过事务日志和回滚日志来实现,确保事务执行失败时可以回滚到事务开始之前的状态,保持数据库的一致性。

隔离性:MySQL使用多版本并发控制(MVCC)来实现隔离性,不同的隔离级别对应着不同的并发控制策略。

持久性:MySQL将事务的undo log(回滚日志)和redo log(重做日志)持久化到磁盘上,以确保事务提交后的持久性。

事务隔离级别

接下来,我们来看看事务隔离级别,MySQL提供了四种不同的隔离级别:

读未提交(Read Uncommitted):在读未提交隔离级别下,一个事务可以看到其他事务尚未提交的修改,这意味着事务之间的操作是相互可见的。虽然读未提交可以提高并发性能,但同时也增加了数据的不一致性和脏读的风险,因此一般不推荐在生产环境中使用。

读已提交(Read Committed):读已提交隔离级别要求事务只能看到其他事务已经提交的修改,这样可以避免脏读的问题。但是在读已提交隔离级别下,其他事务的修改仍然可以影响当前事务的查询结果,因此可能会出现不可重复读的问题。

可重复读(Repeatable Read):在可重复读隔离级别下,事务在执行过程中能够看到其他事务已提交的修改,但不会看到其他事务未提交的修改。这样可以避免不可重复读的问题,但同时也增加了幻读的风险。幻读指的是在同一个事务内,多次执行同样的查询,但得到的结果集却不一致的情况。

串行化(Serializable):串行化隔离级别是最高级别的隔离级别,它要求事务按照顺序逐个执行,避免了并发访问带来的问题。虽然串行化可以确保数据的一致性和完整性,但同时也会降低并发性能,因此在高并发环境下可能不太适用。

MySQL默认隔离级别

在MySQL数据库中,默认采用的事务隔离级别,即可重复读(Repeatable Read)。在可重复读隔离级别下,事务执行期间,其他事务对同一数据的修改是不可见的,这意味着事务开始后,数据库会创建一个一致性快照,事务中的所有查询都会使用该快照中的数据,而不受其他事务的影响。

采用可重复读隔离级别的优点是能够提供较高的数据一致性和稳定性,避免了脏读、不可重复读和幻读等问题。但是,也会导致数据库中的锁资源占用较多,影响了系统的并发性能。

在实际应用中,如果业务对数据的一致性要求较高,并发更新操作较少,那么采用可重复读隔离级别是比较合适的选择。但是,如果系统需要处理大量的并发更新操作,可能需要考虑降低隔离级别,以提高系统的并发性能。

RR和RC使用场景

RR(可重复读)和RC(读已提交)是MySQL数据库中常用的事务隔离级别,在不同的应用场景下具有不同的使用优势。

RR(可重复读):可重复读隔离级别适用于对数据一致性要求较高的场景,例如金融系统、电子商务系统等。在这些场景中,用户对数据的一致性要求很高,需要保证事务在执行期间,对同一数据的多次读取结果保持一致。可重复读隔离级别通过创建事务开始时的一致性快照来实现,确保事务执行期间其他事务对同一数据的修改不可见,从而避免了脏读、不可重复读和幻读等问题。

RC(读已提交):读已提交隔离级别适用于对数据一致性要求不那么严格的场景,例如社交网络、新闻网站等。在这些场景中,用户更加关注数据的实时性,对数据一致性要求相对较低。读已提交隔离级别允许事务读取其他已提交事务的修改,从而提高了并发访问的能力,减少了锁的竞争,提高了系统的性能。但是,读已提交隔离级别可能会导致不可重复读和幻读等问题,因此在一些对数据一致性要求较高的场景中可能不太适用。

表锁(串行化)

表锁是对整个数据库表进行加锁,它可以确保在事务对数据表进行修改时,其他事务不能对同一数据表进行修改,从而保证了数据的一致性和完整性。表锁的粒度较大,可以减少锁的竞争,但同时也会影响系统的并发性能。在高并发环境下,如果使用表锁可能会导致性能瓶颈,因此一般不推荐在生产环境中使用表锁。

行锁(RR、RC)

行锁是对数据库表中的单个数据行进行加锁,它可以确保在事务对数据进行修改时,其他事务不能对同一数据行进行修改,从而避免了数据的冲突和不一致性。行锁的粒度较小,可以最大程度地提高并发性能,减少锁的竞争。但是,行锁也会导致锁资源的占用较多,可能会影响系统的并发性能。

InnoDB支持的行级锁,包括如下几种:

记录锁(Record Lock):锁定单个记录,其他事务无法修改该记录。

间隙锁(Gap Lock):锁定一个范围,防止其他事务在这个范围内插入数据。

Next-key Lock:记录锁和间隙锁的结合,既锁定记录又锁定记录之间的间隙。

共享锁(shared lock, S):多个事务可以同时持有共享锁,用于读取数据。

排他锁(exclusive lock,X):只有一个事务可以持有排他锁,用于修改数据。

意向锁

意向锁是一种辅助性的锁,用来指示事务准备在某个数据库对象(如表或行)上加锁。意向锁分为意向共享锁(IS)和意向排他锁(IX)。

意向共享锁(intention shared lock, IS):事务准备在某个范围内加共享锁。

意向排他锁(intention exclusive lock, IX):事务准备在某个范围内加排他锁。

MVCC多版本并发控制

多版本并发控制(MVCC)是一种常用的并发控制机制,用于在数据库系统中处理读-写冲突,提高系统的并发性能和可靠性。MVCC通过为每个事务创建一个独立的数据版本,并在事务执行期间保持数据的一致性,从而实现了读取操作不阻塞写入操作、写入操作不阻塞读取操作的目标。

MVCC的核心思想是为每个数据行维护多个版本,包括当前版本和历史版本。当一个事务对数据行进行修改时,数据库系统会为该数据行创建一个新的版本,并将原始版本标记为历史版本。其他事务可以继续读取原始版本的数据,而不受修改事务的影响。这样可以避免了传统的锁机制中读-写冲突的问题,提高了系统的并发性能。

在MVCC中,读取操作和写入操作之间不存在直接的冲突,因为读取操作可以读取数据行的任意版本,而不受写入操作的影响。这样可以大大减少锁的竞争,提高了系统的并发性能。另外,MVCC还可以实现非阻塞的读取操作,即使数据行正在被其他事务修改,读取操作也可以继续执行,从而提高了系统的可用性和响应速度。

END

总的来说,数据库事务是保证数据一致性和可靠性的重要手段,了解事务的特性和隔离级别,以及锁的粒度和并发控制机制,对于我们设计高效的数据库应用是非常有帮助的。希望本文能够对大家有所启发,如果有任何疑问或者想法,欢迎在评论区留言讨论哦!

0 阅读:12