王者段位java面试视频
文章目录
王者段位java模式
hystrix 降级 限流
配置 中心 阿波罗,config 等
微服务网关 zuul
rbac模型
用户和角色是多对多的 一个 角色 多个用户,一个用户 多个 角色
权限 和 角色关系,一个权限 多个 角色,一个 角色可以多个权限
常见分布式解决方案
- tcc
- 最大努力尝试
- 最终一致性
rabbitMQ 重复消息
redis 和 mysql 双写一致性的问题
先更新 数据库 再删除缓存
【可能出现的问题,更新完成后, 缓存 还没有删除,可能导致
短暂的数据不一致问题】
你直接回答: 没有十全十美的解决方案
redis 分布式锁
- setnx 的问题:
- 还没有操作完, 这个锁已经过期了
- 解决方案: watchdog 看门狗机制
- 还没有操作完, 这个锁已经过期了
mybatis 二级缓存, hashMap redis 缓存的区别
redis 做分布式缓存, 允许别的服务 同时去使用
数据库的优化
- 分库分表
- 集群
- explain 解释 优化
- 覆盖索引
- 回表
分表策略
- 设置步长
- 按照时间
- 今年的放一张表
- 这个月的放一张表
- hash算法
- 算出 在哪张表
union 的问题
- union 会导致临时表产生
- union和 union all 区别
- union 会去重 【去重的话 会导致效率低】
- union all 不去重
索引
直接回答 b + 树,
b+ 树 和 二叉树 的区别
b+ 树 有多个子节点, 这样压低了 层数 ,如果是 二叉树的话,数据量比较多
层数就比较深, b+ 数压低层数,查询效率就会比较高 (层数越小, 计算机的 Io 次数越少,效率就越高)
myisam 和 innodb 索引上面的区别
my 分为2部分 索引 和 数据文件 是 不一样的 ,数据分离,
查询的话 是先查索引再查数据,会有个回表操作
这里 我直接 说 myisam 是非聚集索引 查询会回表
innodb 如果是 主键索引的话,直接 就是 可以 一次查询出来、
因为 索引和数据是存 一起的,叫做聚集索引
那 innodb 普通索引是非聚集索引, 索引存的是 主键,查询 会有个回表操作。也就是查询2次回表效率低
覆盖索引: 查询的列全部都在命中的索引的条件里面,可以直接从索引里面读取出来,如果触发覆盖索引,就不用回表查询。
innodb 可以支持事务, myisam 不支持事务,只能锁表,更新操作 锁表,导致效率太低
mysql 默认使用 innodb , innodb 和 myisam 区别是 innodb 行锁,myisam 表锁
innodb 锁表怎么解决
1. 更新的时候没有走上索引,导致了全表扫描,就会导致锁表问题,会阻塞后续 读写操作
2. 走索引了,但是没全走上,会有 范围更新的问题,导致 锁住一个比较大的区间【 这样 近似看成是锁表了】
3. 数据库备份的时候,线上的DDL 会导致锁表,
是的,**间隙锁(Gap Lock)**可能导致死锁,但需要具体的场景来触发。为了更清楚了解,以下是相关概念和可能导致死锁的场景:
间隙锁(Gap Lock)的作用
- 范围保护:间隙锁用于保护一个范围内的记录,防止其他事务插入数据,确保事务隔离性。
- 锁定条件:间隙锁在 InnoDB 的 可重复读(REPEATABLE READ) 或更高隔离级别中会被使用,通常在范围查询(
>
,<
,BETWEEN
等)中出现。
间隙锁导致死锁的典型场景
间隙锁引发死锁,通常是由于多个事务在访问同一范围但操作不同数据时发生。例如:
场景 1:两个事务竞争同一范围内不同的插入
假设 table1
有一列 id
,事务 A 和事务 B 的执行顺序如下:
-
事务 A:
1 2
BEGIN; SELECT * FROM table1 WHERE id > 10 FOR UPDATE;
(获取
id > 10
范围的间隙锁) -
事务 B:
1 2
BEGIN; SELECT * FROM table1 WHERE id > 20 FOR UPDATE;
(获取
id > 20
范围的间隙锁) -
如果 事务 A 尝试插入一条
id = 25
的记录,而 事务 B 同时尝试插入一条id = 15
的记录,两者会互相等待,最终导致死锁。
场景 2:不同事务更新或删除时引发范围冲突
假设 table1
中的 id
列已存在记录 10, 20, 30
,事务 A 和事务 B 的操作如下:
-
事务 A:
1 2
BEGIN; DELETE FROM table1 WHERE id = 20;
(间隙锁保护范围
(10, 20)
和(20, 30)
) -
事务 B:
1 2
BEGIN; DELETE FROM table1 WHERE id = 10;
(间隙锁保护范围
(null, 10)
和(10, 20)
) -
两者都需要对方释放锁才能完成操作,从而造成死锁。
如何避免间隙锁导致死锁
-
使用合适的事务隔离级别:
- 在不需要间隙锁的场景下,降低隔离级别到 读已提交(READ COMMITTED) 可以减少锁争用。
-
明确访问顺序:
- 在多个事务中,尽量保证对资源的访问顺序一致,避免互相等待。
-
优化查询条件:
- 尽量避免范围查询(
>
、<
、BETWEEN
等)在频繁插入、更新的场景下使用。
- 尽量避免范围查询(
-
使用索引:
- 在查询条件中尽量使用唯一索引,减少间隙锁的范围。
如何检测和分析死锁
-
查看死锁日志: 在 MySQL 中可以通过以下命令查看最近的死锁信息:
1
SHOW ENGINE INNODB STATUS\G;
-
分析事务冲突: 根据日志中的锁等待链,找到产生死锁的事务及其操作,优化对应的 SQL。
间隙锁虽能提高事务隔离性,但需要注意它可能带来的锁争用和死锁风险,特别是在高并发环境下。
你说得对,两个事务分别获取 id > 10
和 id > 20
的间隙锁时,确实不会直接互相阻塞。但为什么仍可能出现死锁?这需要结合 MySQL 间隙锁的特性和操作场景来分析。
原因:间隙锁不只锁住范围,还涉及插入意向锁
在 MySQL 的 InnoDB 引擎中,**间隙锁(Gap Lock)**通常与插入意向锁(Insert Intention Lock)结合使用,这种组合可能引发死锁。以下是两种常见的死锁触发机制:
场景 1:间隙锁 + 插入意向锁引发死锁
假设表 table1
的 id
列已经存在数据 10, 20, 30
,事务 A 和事务 B 的操作如下:
-
事务 A:
1 2
BEGIN; SELECT * FROM table1 WHERE id > 10 FOR UPDATE;
- 锁住范围
(10, +∞)
的间隙,并对现有记录(如20, 30
)加行锁。
- 锁住范围
-
事务 B:
1 2
BEGIN; SELECT * FROM table1 WHERE id > 20 FOR UPDATE;
- 锁住范围
(20, +∞)
的间隙,并对现有记录(如30
)加行锁。
- 锁住范围
-
接下来,事务 A 和 B 各自尝试插入一条新记录:
- 事务 A 插入
id = 25
,需要检查(20, +∞)
的间隙锁(被事务 B 锁住)。 - 事务 B 插入
id = 15
,需要检查(10, 20)
的间隙锁(被事务 A 锁住)。
- 事务 A 插入
-
结果:两者互相等待对方释放锁,从而死锁。
场景 2:间隙锁范围重叠引发死锁
虽然事务分别请求 id > 10
和 id > 20
的锁,但由于 InnoDB 间隙锁的实现方式,可能会出现范围锁重叠,从而导致死锁。假设表中已有记录 10, 20, 30
,事务 A 和事务 B 的操作如下:
-
事务 A:
1 2
BEGIN; SELECT * FROM table1 WHERE id > 10 FOR UPDATE;
- 锁住范围
(10, +∞)
,包括(10, 20)
和(20, +∞)
两段间隙。
- 锁住范围
-
事务 B:
1 2
BEGIN; SELECT * FROM table1 WHERE id > 20 FOR UPDATE;
- 理论上锁住范围
(20, +∞)
。
- 理论上锁住范围
-
关键点:锁范围的实际实现
InnoDB 会在请求范围锁时,将操作扩展到整个范围的一部分(包括锁住相关行),因此:- 事务 A 锁住了
(10, 20)
和(20, 30)
。 - 事务 B 锁住了
(20, 30)
和(30, +∞)
。
- 事务 A 锁住了
-
发生冲突:
- 如果事务 A 试图访问
id = 30
或尝试插入记录到(20, 30)
,而事务 B 试图访问id = 20
或插入到(10, 20)
,两者就会陷入等待。
- 如果事务 A 试图访问
为什么范围锁会扩展?
这是 MySQL InnoDB 为了确保事务隔离性的一种策略。在间隙锁的场景下,InnoDB 通常会锁住查询范围涉及的行以及相关的间隙,而这些范围有时会相互重叠,从而产生冲突。
如何避免这种死锁?
-
明确索引范围:
- 如果可以,避免使用范围查询(
>
、<
等)直接加锁;考虑具体的记录加锁,或通过唯一索引精确定位行。
- 如果可以,避免使用范围查询(
-
调整事务操作顺序:
- 设计事务时,尽量保持一致的操作顺序,避免不同事务互相抢占资源。
-
使用更低的隔离级别:
- 在业务允许的情况下,降低隔离级别到 READ COMMITTED,此时 InnoDB 会减少间隙锁的使用。
-
使用间隙锁诊断工具:
- 通过
SHOW ENGINE INNODB STATUS\G
检查死锁日志,找出具体冲突位置,优化 SQL 语句。
- 通过
总结来说,虽然两个事务锁住的范围是 id > 10
和 id > 20
,看似没有直接冲突,但由于间隙锁的实际实现以及可能的插入操作,两者会间接引发死锁。这也是为什么即使范围不同,死锁仍会发生。
文章作者 LYR
上次更新 2021-08-17