“同学,能说说MySQL事务的隔离级别吗?”
“呃…就是读未提交、读已提交…还有那个可重复读和串行化!”
“那这些隔离级别具体解决了什么问题呢?”
(当场石化)
作为面过无数大厂的过来人,今天就把MySQL面试里那些高频必杀题掰开了揉碎了讲!准备好迎接暴击了吗?(建议收藏后反复观看)
一、事务的ACID到底是啥?(必考题!)
面试官一开口问这个,我就知道他要开始挖坑了!先背标准答案:
- Atomicity(原子性):事务要么全成功,要么全失败(比如转账不能只扣钱不加钱)
- Consistency(一致性):数据要符合业务规则(比如账户余额不能为负)
- Isolation(隔离性):多个事务并发时互不干扰
- Durability(持久性):事务提交后数据永久保存
但是! 这里有个大坑:一致性到底是谁保证的?(灵魂拷问)
- 数据库只保证原子性、隔离性、持久性
- 一致性其实靠业务代码+数据库共同维护!(敲黑板)
比如你非要在代码里写余额-1000不检查,数据库可不会拦着你!
二、索引优化连环炮(送命题)
2.1 为什么加了索引还是慢?
别急着甩锅给索引!先看看这些情况你中招没:
- 索引字段用了函数/表达式(
WHERE YEAR(create_time)=2023
) - 隐式类型转换(varchar字段传了数字)
- 最左前缀失效(建了(a,b,c)索引却只用b,c条件)
- 回表查询太多(select * 用覆盖索引啊!)
真实案例:某电商项目查订单慢了,EXPLAIN一看——好家伙,明明有联合索引,却因为order by create_time
导致filesort!(解决方法:把create_time加到联合索引最后)
2.2 10亿数据怎么快速分页?
LIMIT 1000000,10
会先查1000010条再扔掉,不慢才怪!试试这两招:
方案一:
SELECT * FROM table WHERE id > 上次最大ID LIMIT 10
方案二(复杂条件):
SELECT * FROM table
INNER JOIN (SELECT id FROM table WHERE ... LIMIT 1000000,10) AS tmp
USING(id)
三、锁机制:死锁是怎么找上你的?
3.1 行锁升级表锁(血案现场)
当你的SQL索引失效时,行锁会直接升级为表锁!比如:
UPDATE users SET age=18 WHERE name LIKE '%王%';
如果name字段没索引,恭喜你——全表锁住了!
3.2 死锁名场面
事务A:
UPDATE account SET balance=100 WHERE id=1;
UPDATE account SET balance=200 WHERE id=2;
事务B:
UPDATE account SET balance=300 WHERE id=2;
UPDATE account SET balance=400 WHERE id=1;
当两个事务以不同顺序更新资源时,死锁就诞生了!(MySQL会自动检测并回滚代价小的事务)
四、灵魂拷问:MVCC原理是什么?
这个问题的杀伤力在于——很多开发者用了多年事务,却不知道底层机制!
MVCC(多版本并发控制)核心三板斧:
- 每个事务有唯一事务ID(递增)
- 每行数据有
DB_TRX_ID
(最后更新它的事务ID)和DB_ROLL_PTR
(回滚指针) - ReadView机制决定能看到哪个版本的数据
举个栗子🌰:
- 事务A(ID=100)开启,创建ReadView
- 事务B(ID=101)更新了某行数据
- 事务A查询时,发现该行
DB_TRX_ID=101
> 自己的ReadView,就顺着回滚指针找旧版本
这就实现了可重复读隔离级别!(是不是比直接背概念清晰多了?)
五、终极难题:主从延迟怎么办?
5.1 延迟产生的原因
- 主库并发写入,从库单线程重放
- 大事务执行时间长(比如全表更新)
- 从库服务器配置差
5.2 解决方案大乱斗
- 半同步复制:主库等至少一个从库收到日志再返回
- 并行复制:MySQL 5.7后的多线程复制
- 缓存双写:更新数据时同时写缓存
- 强制路由:关键业务查询强制走主库(但会增加主库压力)
血泪教训:某金融项目因为主从延迟导致用户看到"余额消失",最后只能用SHOW SLAVE STATUS
查延迟,关键操作全部切主库查询!
六、开发必备冷知识
6.1 count(*) VS count(1) 谁更快?
实测结果:在MySQL 8.0中,两者性能完全一致!优化器会自动处理。但是count(字段)
会慢,因为要判断是否为NULL。
6.2 datetime和timestamp怎么选?
- datetime:支持1000-9999年,物理存储8字节
- timestamp:支持1970-2038年,自动转换时区,4字节
建议:如果需要时区转换就用timestamp,否则用datetime
最后说两句
MySQL面试最可怕的地方在于——你以为会写CRUD就够了,其实每个问题都能挖出十八层地狱!建议小伙伴们:
- 亲手用EXPLAIN分析慢查询
- 用
SHOW ENGINE INNODB STATUS
看死锁日志 - 一定要自己搭主从环境体验复制延迟
记住,面试官最喜欢问的其实就三个方向:事务原理、索引优化、高可用方案。吃透这些核心点,MySQL面试直接横着走!(当然别忘了结合项目实际场景哦)