Java总结-数据库
一、数据库的隔离级别?
1、 Uncommitted(读未提交)
- 事务可以读取其他事务未提交的数据(脏读)。
- 可能会出现脏读(Dirty Read)、不可重复读(Non-repeatable Read)和幻读(Phantom Read)。
- 并发性能高,但数据一致性差。
2、Read Committed(读已提交)
- 事务只能读取已经提交的数据。
- 避免脏读,但仍然可能出现不可重复读和幻读。
- 提高数据一致性,但可能影响性能。
3、Repeatable Read(可重复读)
- 事务在执行期间,多次读取相同的数据时,保证读取结果一致。
- 避免脏读和不可重复读,但可能仍然会有幻读。
- MySQL InnoDB 通过 MVCC + Gap Lock 解决幻读问题。
4、Serializable(可串行化)
- 最高隔离级别,相当于事务串行执行,避免所有并发问题(脏读、不可重复读、幻读)。
- 通过行级锁或表级锁实现,并发性能最差,适用于高数据一致性要求的场景。
Tips
SQL Server、Oracle 默认的隔离级别:Repeatable Read(可重读)级别。
Oracle 默认的隔离级别:Read Committed(读取已提交的)级别。
5、脏读和幻读的区别
脏读和幻读都是数据库事务中的一致性问题,但它们本质上不一样,咱们来对比一下:
🎯 1. 脏读 (Dirty Read)
- 定义:事务A读取了事务B尚未提交的数据,若B回滚,A就读到了无效数据。
- 场景示例:
- 事务B修改了一条记录但还没提交,事务A读取了这条数据。
- 结果事务B回滚了,事务A读取的数据就成了“脏数据”。
例子:
- 事务B将用户余额从100改成200,但未提交。
- 事务A读取了余额200。
- 事务B回滚,恢复余额为100。
- 事务A此时拿到的是错误的200。
- 解决办法:
READ COMMITTED
及以上隔离级别可以防止脏读。
🎯 2. 幻读 (Phantom Read)
- 定义:事务A在读取数据集后,事务B插入、删除了数据,导致事务A再次读取时发现数据“多了”或“少了”,就像“幻觉”一样。
- 场景示例:
- 事务A统计订单表的记录有10条。
- 事务B插入了新订单,事务A再次查询,发现有11条,出现“幻读”。
例子:
- 事务A查询
SELECT COUNT(*) FROM orders;
结果为10条。 - 事务B插入了1条新订单并提交。
- 事务A再次查询,发现结果变成了11条。
- 解决办法:
REPEATABLE READ
级别可以防止“不可重复读”,但防不了“幻读”,要用**SERIALIZABLE
** 或 悲观锁来解决幻读。
🔥 总结对比
特点 | 脏读 (Dirty Read) | 幻读 (Phantom Read) |
---|---|---|
定义 | 读取到未提交的数据 | 读取到新增/删除的数据 |
表现 | 数据还没提交就被读取 | 数据条数“变化了” |
产生原因 | 事务回滚导致数据失效 | 新增、删除导致数据集变化 |
隔离级别 | READ COMMITTED 防止 | SERIALIZABLE 防止/REPEATABLE 下MVCC + Gap Lock防止 |
二、讲一讲MySql的索引?
1、索引的原理
2、索引的类型
3、如何创建合理的索引?
4、索引如何优化?
三、聚集索引和非聚集索引的区别?
1、聚集索引
2、非聚集索引
3、回表了解吗?
四、索引失效的场景有哪些?
1、联合索引不满足最左匹配原则
Tips
最左匹配原则不仅是“必须从最左列开始”,还涉及到“匹配过程中遇到范围查询 (<, >, BETWEEN, LIKE) 就会提前终止索引继续匹配”。
比如索引 (a, b, c),查询 WHERE a=1 AND b>10 AND c=3,c 就用不上索引了。
2、like查询的前导模糊匹配
Tips
此种情况其实就是最左匹配原则,如下情况:
LIKE 'keyword%' ✅ 可以走索引
LIKE '%keyword%' ❌ 索引失效(前置 % 导致全表扫描)
3、参与运算或使用函数
Tips
运算(WHERE salary*2 > 2000):索引列在运算后变成了表达式结果,索引用不上。
函数(WHERE LEFT(name, 3) = 'Tom'):函数改变了索引列的值,也就失效了。
4、类型隐式转换
Tips
比如 phone 是 VARCHAR 类型,查询 WHERE phone = 123456789,会触发类型转换(把字符串转数字),导致索引失效。
改写成:WHERE phone = '123456789' ✅ 才能走索引。
5、列使用OR操作
Tips
查询条件使用 OR 关键字,其中一个字段没有创建索引,则会导致整个查询语句索引失效;
OR 里有范围查询(<、>、BETWEEN、LIKE '%...' 等),索引也可能失效。
6、两列做比较(等于/不等于)
Tips
WHERE a = b ✅ 可以走索引(前提是 a、b 是索引列)
WHERE a != b ❌ 索引失效(因为范围太大,优化器更倾向全表扫描)
7、IS NOT NULL、NOT IN和NOT EXISTS
Tips
IS NOT NULL ✅ 索引可能失效(要看版本和索引设计)
NOT IN ❌ 一般失效,但 NOT IN (索引列) 有时能优化成 Anti-Join
NOT EXISTS ✅ MySQL 8.0 优化了 NOT EXISTS,有时走索引
例如:
SELECT * FROM orders WHERE customer_id IS NOT NULL; -- 可能索引失效
SELECT * FROM orders WHERE customer_id NOT IN (1,2,3); -- 索引一般失效
8、 order by导致索引失效
Tips
单列索引排序 ✅ 能走索引
联合索引排序 ✅ 要按索引顺序排序,不能乱
排序方向必须一致,ORDER BY a ASC, b DESC ❌ 索引失效
例如:
-- 索引 (a, b)
SELECT * FROM users ORDER BY a, b; -- ✅ 走索引
SELECT * FROM users ORDER BY b, a; -- ❌ 索引失效
9、参数不同导致索引失效
Tips
MySQL 优化器会判断 "索引扫描" 和 "全表扫描" 的成本:
如果查询结果占比 <30%,走索引
如果查询结果占比 >30%,全表扫描更快
例如:
SELECT * FROM users WHERE age > 10; -- 小表走索引,大表直接全表扫描
10、Mysql优化器的其他优化策略
Tips
比如优化器认为在某些情况下,全表扫描比走索引快,则它就会放弃索引:
Union 合并:多个单列索引组合查询
Intersection 合并:多个条件筛选索引交集
Sort-Union 合并:排序+索引合并
五、Mysql的存储引擎对比
1、MyISAM
(1)不支持事务,但是每次查询都是原子的;
(2)支持表级锁,即每次操作是对整个表加锁;
(3)存储表的总行数;
(4)一个 MYISAM 表有三个文件:索引文件、表结构文件、数据文件;
(5)采用菲聚集索引,索引文件的数据域存储指向数据文件的指针。辅索引与主索引基本一致,但是辅索引不用保证唯一性。
2、InnoDb
(1)支持 ACID 的事务,支持事务的四种隔离级别;
(2)支持行级锁及外键约束:因此可以支持写并发;
(3)不存储总行数:
(4)一个 InnoDb 引擎存储在一个文件空间(共享表空间,表大小不受操作系统控制,一个表可能分布在多个文件里),也有可能为多个 (设置为独立表空,表大小受操作系统文件大小限制,一般为 2G),受操作系统文件大小的限制;
(5)主键索引采用聚集索引(索引的数据域存储数据文件本身),辅索引的数据域存储主键的值;因此从辅索引查找数据,需要先通过辅 索引找到主键值,再访问辅索引;最好使用自增主键,防止插入数据时,为维持 B+树结构,文件的大调整。
六、Explain关键字的介绍?
七、Mysql的几种锁对比?
更多详情请查看 Mysql锁