Mysql
1.Mysql - 存储引擎
1.1 MySQL ⽀持哪些存储引擎?默认使⽤哪个?
Mysql默认存储引擎通过 SHOW ENGINES 命令可以看到,默认是 InnoDB 并且,从图中可以看出,也只有 InnoDB支持事务,
1.2 MyIsam 和 InnoDB 有什么区别?
事务支持:
- MyISAM 不支持事务,它是基于表级锁定的存储引擎,只支持表级别的锁定。因此,对于并发性能要求高、需要事务支持的应用场景不适合。
- InnoDB 支持事务,基于行级锁定的存储引擎,可以支持更高的高并发性,同时提供了 ACID(原子性、一致性、隔离性、持久性)特性,适合需要事务支持的应用场景。
行级锁定:
- MyISAM 使用表级锁定,即在对表进行读写操作时会锁定整张表,导致并发性能较差。
- InnoDB 使用行级锁定,即在对表进行读写操作只锁定所涉及的行,提高了并发行嫩,降低锁冲突。
外键约束:
- MyISAM 不支持外键约束,需要在应用层进行控制。
- InnoDB 支持外键约束,可以通过 FOREIGN KEY 约束来维护表之间的关系,保证数据的完整性。
崩溃恢复:
- MyISAM 在崩溃后恢复的速度较快,因为是表级锁所以恢复快。
- InnoDB 恢复速度慢,因为它使用的是行级锁定和事务日志,需要进行恢复和回滚操作,但是可以提供更好的数据完整性和一致性。
索引结构:
- MyISAM 使用B树索引结构,适用于读密集的查询场景,对于查询较多,更新较少的场景性能较好。
- InnoDB 使用B+树索引结构,同时支持聚簇索引,适用于读并发场景。
2.Mysql - 事务
2.1 事务的四大特性?
事务(Transaction)是指作为单个逻辑工作单元执行的一系列操作,要么全部执行成功,要么全部不执行,具有以下四大特性,简称为 ACID 特性:
原子性(Atomicity):
- 原子性指的是事务是一个不可分割的工作单元,要么全部执行成功,要么全部不执行。即使在事务执行过程中发生了错误或者异常,也会将事务回滚到最初状态,不会留下部分执行的痕迹。
- 例:银行转账操作中,从一个账户扣款向另一个账户转款应该是一个原子性操作,要么全部成功,要么全部失败,不能只扣款不转款或者只转款不扣款。
一致性(Consistency):
- 一致性指的是事务执行前后,数据库的状态应该保持一致性。即使在事务执行过程中发生了错误或者异常,也不会破坏数据库的完整性和约束。
- 例:当进行银行转账时,如果转出账户扣款成功,但转入账户未能成功接收款项,那么银行系统应该保持一致性,将扣款操作回滚,确保账户余额保持一致。
隔离性(Isolation):
- 隔离性指的是并发执行的事务之间应该相互隔离,互不干扰,每个事务都应该感觉到它是在独立运行的。
- 例:在并发环境下,如果两个事物同时对统一数据进行读写操作,隔离性要求系统能够保证每个事物读取到的数据是一致的,即使在另一个事务修改数据的过程中。
持久性(Durability):
- 持久性指的是事务一但提交成功,对数据库的修改就是永久性的,即使系统发生故障或者重启,数据库的状态也应该能够恢复到食物提交后的状态。
这四大特性确保了事务的可靠性和一致性,是保证数据库操作安全和正确性的重要基础。在设计和开发应用程序时,需要根据业务需求和数据操作的特点合理应用这些特性,以确保系统的可靠性和稳定性。
2.2 并发事务带来了那些问题?不可重复度和幻读有什么区别?
脏读(Dirty Read):
- 当一个事物读取到另一个事务尚未提交的数据时,发生脏读。如果第二个事物在稍后回滚,则第一个事务读取到的数据讲是无效的,导致不一致的结果。
不可重复度(Non-Repeatable Read):
- 在一个事务内多次读取到同一数据,在事务执行期间,另一个事务对该数据进行了修改并提交,导致事物多次读取到同一数据时得到了不同的结果。虽然两次读取之间数据并未改变,但由于其他事物的修改,导致了不一致的读取结果。
幻读(Phantom Read):
- 在一个事物内读取到某个范围的数据时,另一个事务在该范围内插入新的数据并提交,导致事物再次读取该范围的数据时,发现多出了一些数据(“幻行”)。虽然两次读取之间没有其他事物对数据做修改,但由于其他事物的插入操作,导致了不一致的读取结果。
代码实例: 假设有一张名为 order 的订单表,包含 order_id
和 order_status
字段,初始状态如下:
order_id order_status
1 'pending'
2 'pending'
不可重复读:
// 事务1
begin transaction;
select * from orders where order_id = 1;
// 返回结果: order_id = 1, order_status = 'pending'
// 事务2
begin transaction;
update orders set order_status = 'completed' where order_id = 1;
commit;
// 事务1
select * from orders where order_id = 1;
// 返回结果: order_id = 1, order_status = 'completed'
在事务1中,第一次读取 order_id = 1 的数据时,order_status 为 pending。但在事务2中,order_id = 1 的数据被更新为 ‘completed’。在事务1再次读取同一个数据时,order_status 已经发生了改变,这就是不可重复读的情况。
幻读:
// 事务1
begin transaction;
select * from orders where order_id >= 1 and order_id <= 2;
// 返回结果: order_id = 1, order_status = 'pending'; order_id = 2, order_status = 'pending'
// 事务2
begin transaction;
insert into orders (order_id, order_status) values (3, 'pending');
commit;
// 事务1
select * from orders where order_id >= 1 and order_id <= 2;
// 返回结果: order_id = 1, order_status = 'pending'; order_id = 2, order_status = 'pending'; order_id = 3, order_status = 'pending'
在事务1中,第一次读取 order_id 在范围内的数据时,只有两条记录。但在事务2中,插入了一条新的订单记录。在事务1再次读取同一范围的数据时,发现多出了一条记录,这就是幻读的情况。
除了脏读、不可重复读和幻读之外,还有一些其他可能的并发问题:
丢失更新(Lost Update):
- 当两个事务同时读取同一数据,并且都对其进行修改后提交,但由于最后提交的事务覆盖了先前的修改,导致先前的修改丢失,这被称为丢失更新。
读取未提交数据(Read Uncommitted):
- 一个事务可以读取另一个事务尚未提交的数据,这可能会导致脏读。
更新丢失(Update Lost):
- 两个事务同时读取同一数据,并且都对其进行修改后提交,但由于事务的提交顺序不同,导致某一个事务的修改被另一个事务的修改所覆盖,这被称为更新丢失。
2.3 Mysql 事务隔离级别?默认是什么级别?
READ UNCOMMITTED(读未提交):
- 允许事务读取尚未提交的数据变更,可能会导致脏读、不可重复读和幻读问题。
READ COMMITTED(读已提交):
- 保证一个事务所读取的数据已经被提交,禁止脏读,但是可能会出现不可重复读和幻读的问题。
REPEATABLE READ(可重复读):
- 对同一字段的多次读取结果是一致的,除非该字段被当前事务修改。在事务执行期间禁止其他事务对该数据进行修改,可以避免脏读和不可重复读问题,但仍可能出现幻读问题。
SERIALIZABLE(串行化):
- 最高的隔离级别,通过强制事务串行执行来避免脏读、不可重复读和幻读,但是性能较差,通常需要较长的锁定时间。
在 MySQL 中,默认的事务隔离级别是 REPEATABLE READ(可重复读)。这意味着当你启动一个新的事务时,它的隔离级别会默认设置为可重复读。如果需要更改隔离级别,可以在事务内部使用 SET TRANSACTION 命令进行设置,例如:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
或者在连接数据库之后,可以使用以下语句设置全局的隔离级别:
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
需要注意的是,事务隔离级别的选择应根据具体的业务需求和对并发问题的容忍程度来确定,需要权衡事务的隔离性和性能之间的关系。
2.4 Mysql 的隔离级别是基于锁实现的吗?
MySQL 的事务隔离级别是基于锁实现的,但是具体的实现方式会根据不同的存储引擎而有所不同。
在 InnoDB 存储引擎中,MySQL 使用了多版本并发控制(MVCC)来实现不同隔离级别下的并发控制,而不仅仅依赖于锁。MVCC 通过记录数据的多个版本来支持不同的隔离级别,从而实现了高并发的读取操作,避免了大部分情况下的锁竞争问题。
具体来说,在 InnoDB 中,读操作不会阻塞写操作,写操作也不会阻塞读操作,因为它们都采用了多版本并发控制,通过版本控制和事务的启动时间戳来实现对事务的隔离。
当然,在某些情况下,InnoDB 也会使用锁来实现特定的隔离级别。例如,对于 SERIALIZABLE 隔离级别,InnoDB 会使用锁来确保事务的串行执行,以避免幻读问题。
总的来说,MySQL 的事务隔离级别是基于多版本并发控制和锁机制共同实现的,以保证事务的隔离性和并发性。
2.5 InnoDB 对 MVCC 的具体实现
InnoDB 存储引擎通过多版本并发控制(MVCC)来实现对不同事务隔离级别的支持,其具体实现包括以下几个关键组成部分:
版本号:
- 每行数据都会存储一个版本号,用来标识该行数据的版本。在每次对数据进行修改时,都会增加版本号,保证数据的历史版本得以保存。
undo log:
- InnoDB 使用 undo log 来保存事务对数据的修改操作,即在事务对数据进行修改时,将原始数据保存到 undo log 中,而不是直接修改数据。这样可以保留数据的历史版本,以支持不同事务之间的并发操作。
Read View:
- 每个事务在启动时都会创建一个 Read View,用来确定该事务能够看到的数据版本范围。Read View 包含了事务启动时的系统版本号(事务启动时刻),用来确定事务启动时已经提交的事务版本号范围。
事务版本号:
- 每个事务都会被分配一个唯一的事务版本号。在执行 SELECT 操作时,会根据事务版本号和行数据的版本号来确定该事务能够看到的数据版本。
基于以上几个关键组成部分,InnoDB