记一次杭州百世快递面试题(海外ERP)
本文最后更新于218 天前,其中的信息可能已经过时,如有错误请发送邮件到[email protected]

全程没问过很多Java上的东西,都是MySQL上的。😔

B树和B+树

B树

B 树是一种多路平衡查找树,为了更形象的理解,(我们来看这张图)。二叉树,每个节点支持两个分支的树结构,相比于单向链表,多了一个分支。

二叉查找树,在二叉树的基础上增加了一个规则,左子树的所有节点的值都小于它的根节点,右子树的所有子节点都大于它的根节点

二叉查找树会出现斜树问题(如下图),导致时间复杂度增加,因此又引入了一种平衡二叉树,它具有二叉查找树的所有特点,同时增加了一个规则:”它的左右两个子树的高度差的绝对值不超过 1“。平衡二叉树会采用左旋、右旋的方式来实现平衡。

而 B 树是一种多路平衡查找树,它满足平衡二叉树的规则,但是它可以有多个子树,子树的数量取决于关键字的数量,比如下图中根节点有两个关键字 3 和 5,那么它能够拥有的子路数量=关键字数+1

因此从这个特征来看,在存储同样数据量的情况下,平衡二叉树的高度要大于 B 树。

B+树

B+树,其实是在 B 树的基础上做的增强,最大的区别有两个:

  1. B 树的数据存储在每个节点上,而 B+树中的数据是存储在叶子节点,并且通过链表的方式把叶子节点中的数据进行连接。

  2. B+树的子路数量等于关键字数

这个是 B 树的存储结构,从 B 树上可以看到每个节点会存储数据

这个是 B+树,B+树的所有数据是存储在叶子节点,并且叶子节点的数据是用双向链表关联的。

B 树和 B+树,一般都是应用在文件系统和数据库系统中,用来减少磁盘 IO 带来的性能损耗

以 Mysql 中的 InnoDB 为例,当我们通过 select 语句去查询一条数据时,InnoDB 需要从磁盘上去读取数据,这个过程会涉及到磁盘 IO 以及磁盘的随机 IO(如图所示)我们知道磁盘 IO 的性能是特别低的,特别是随机磁盘 IO。

因为,磁盘 IO 的工作原理是,首先系统会把数据逻辑地址传给磁盘,磁盘控制电路按照寻址逻辑把逻辑地址翻译成物理地址,也就是确定要读取的数据在哪个磁道,哪个扇区。

为了读取这个扇区的数据,需要把磁头放在这个扇区的上面,为了实现这一个点,磁盘会不断旋转,把目标扇区旋转到磁头下面,使得磁头找到对应的磁道,这里涉及到寻道事件以及旋转时间。

很明显,磁盘 IO 这个过程的性能开销是非常大的,特别是查询的数据量比较多的情况下。

所以在 InnoDB 中,干脆对存储在磁盘块上的数据建立一个索引,然后把索引数据以及索引列对应的磁盘地址,以 B+树的方式来存储。

如图所示,当我们需要查询目标数据的时候,根据索引从 B+树中查找目标数据即可,由于 B+树分路较多,所以只需要较少次数的磁盘 IO 就能查找到。

为什么用 B 树或者 B+树来做索引结构?

原因是 AVL 树的高度要比 B 树的高度要高,而高度就意味着磁盘 IO 的数量。所以为了减少磁盘 IO 的次数,文件系统或者数据库才会采用 B 树或者 B+树。

MySQL如何防止死锁,在java代码上如何进行规避

MySQL死锁的发生

死锁是指两个或多个事务相互等待对方释放资源,导致所有事务都无法继续执行的状态。在MySQL中,死锁通常发生在以下情况:

  1. 交叉锁请求:两个事务分别持有对方需要的锁,并且都在等待对方释放锁。
  2. 锁升级:一个事务从较低级别的锁(如行锁)升级到较高级别的锁(如表锁),而另一个事务持有该表的锁。
  3. 锁超时:一个事务等待锁的时间超过了设定的超时时间,导致锁请求失败。

如何防止死锁

  1. 事务隔离级别

    • 使用较低的事务隔离级别(如READ COMMITTED)可以减少锁的持有时间,从而降低死锁的可能性。
    • 但要注意,较低的隔离级别可能会导致数据一致性问题。
  2. 事务顺序

    • 确保所有事务以相同的顺序访问资源。例如,如果多个事务都需要锁定表A和表B,那么所有事务都应该先锁定表A,再锁定表B。
  3. 事务超时

    • 设置事务的超时时间,如果事务等待锁的时间超过了超时时间,则自动回滚事务。
  4. 锁粒度

    • 尽量使用较小的锁粒度(如行锁),而不是较大的锁粒度(如表锁),以减少锁冲突的可能性。
  5. 避免长事务

    • 尽量缩短事务的执行时间,减少锁的持有时间。

在Java代码上如何进行规避

  1. 事务管理

    • 使用Spring框架的事务管理功能,确保事务的隔离级别、传播行为和超时时间设置合理。

    • 例如,使用@Transactional注解来管理事务:

      @Transactional(isolation = Isolation.READ_COMMITTED, timeout = 30)
      public void performTransaction() {
       // 事务逻辑
      }
  2. 资源顺序

    • 在代码中确保所有事务以相同的顺序访问数据库资源。例如,如果多个事务都需要更新表A和表B,确保所有事务都先更新表A,再更新表B。
  3. 锁超时处理

    • 在代码中捕获锁超时异常(如LockTimeoutException),并进行相应的处理,例如回滚事务或重试。

    • 例如:

      try {
       performTransaction();
      } catch (LockTimeoutException e) {
       // 处理锁超时异常
       TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      }
  4. 重试机制

    • 对于可能发生死锁的场景,可以实现重试机制。如果检测到死锁,可以等待一段时间后重试事务。

    • 例如:

      int retryCount = 3;
      for (int i = 0; i < retryCount; i++) {
       try {
           performTransaction();
           break;
       } catch (DeadlockException e) {
           if (i == retryCount - 1) {
               throw e;
           }
           Thread.sleep(1000); // 等待1秒后重试
       }
      }
  5. 监控和日志

    • 监控数据库的死锁情况,并记录死锁日志。通过分析日志,可以找出死锁的根本原因,并进行优化。

自身优化

在MySQL的Server引擎中,为了防止死锁,做了以下几方面的设计和优化:

1. 死锁检测

MySQL内置了死锁检测机制,通过定期检查事务之间的依赖关系来识别死锁。当检测到死锁时,MySQL会选择一个事务作为“牺牲品”,并回滚该事务,从而打破死锁状态。

  • 死锁检测算法:MySQL使用了一种称为“等待图”(Wait-For Graph)的算法来检测死锁。等待图是一个有向图,其中节点表示事务,边表示事务之间的等待关系。如果图中存在环路,则表示发生了死锁。

2. 自动回滚

当死锁被检测到时,MySQL会自动选择一个事务进行回滚,通常是选择代价最小的事务(即回滚该事务所需的工作量最小)。被回滚的事务会收到一个ER_LOCK_DEADLOCK错误。

  • 回滚策略:MySQL会选择一个事务进行回滚,而不是简单地终止所有事务。这样可以最小化对系统的影响。

3. 锁超时

MySQL允许为锁请求设置超时时间。如果一个事务在等待锁的时间超过了设定的超时时间,MySQL会自动放弃该锁请求,并回滚事务。

  • innodb_lock_wait_timeout:这是一个全局变量,用于设置锁等待的超时时间(以秒为单位)。默认值通常是50秒。

    SET innodb_lock_wait_timeout = 30; -- 设置锁等待超时时间为30秒

4. 事务隔离级别

MySQL支持多种事务隔离级别,不同的隔离级别对锁的使用有不同的影响。较低的隔离级别(如READ COMMITTED)可以减少锁的持有时间,从而降低死锁的可能性。

  • 隔离级别设置:可以通过SQL语句或配置文件设置事务隔离级别。

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

5. 锁粒度控制

MySQL的InnoDB存储引擎支持多种锁粒度,包括行锁、页锁和表锁。通过合理选择锁粒度,可以减少锁冲突的可能性。

  • 行锁:InnoDB默认使用行锁,行锁的粒度较小,可以减少锁冲突。
  • 表锁:在某些情况下,InnoDB会自动升级为表锁,但这通常是为了提高性能或避免死锁。

6. 事务顺序控制

虽然MySQL本身不直接控制事务的执行顺序,但通过合理的事务设计和应用程序逻辑,可以减少死锁的发生。例如,确保所有事务以相同的顺序访问资源。

7. 死锁日志记录

MySQL会记录死锁信息,包括死锁发生的时间、涉及的事务、锁的类型等。这些日志信息可以帮助DBA分析死锁的原因,并进行优化。

  • 死锁日志:死锁信息通常记录在MySQL的错误日志中,可以通过以下命令查看:

    SHOW ENGINE INNODB STATUS;

如何防止行锁变成表锁

行锁和表锁的发生

在MySQL的InnoDB存储引擎中,锁的粒度可以分为行锁和表锁。行锁和表锁的发生主要与以下因素有关:

1. 行锁

行锁(Row-Level Locking)是InnoDB的默认锁机制。行锁只锁定特定的行,而不是整个表。行锁的粒度较小,可以提高并发性能,但也会增加锁管理的复杂性。

  • 行锁的发生
    • 当一个事务对某一行进行修改(如UPDATEDELETE)时,InnoDB会自动对该行加锁。
    • 如果事务使用了SELECT ... FOR UPDATESELECT ... LOCK IN SHARE MODE语句,InnoDB也会对查询到的行加锁。

2. 表锁

表锁(Table-Level Locking)是锁定整个表的锁机制。表锁的粒度较大,会阻塞其他事务对整个表的访问,因此并发性能较差。

  • 表锁的发生
    • 显式表锁:使用LOCK TABLES语句可以显式地对表加锁。
    • 隐式表锁:在某些情况下,InnoDB会自动将行锁升级为表锁,例如:
    • 当一个事务对某个表进行全表扫描时,InnoDB可能会将行锁升级为表锁,以提高性能。
    • 当一个事务对某个表进行DDL操作(如ALTER TABLE)时,InnoDB会自动对该表加表锁。

如何防止行锁变成表锁

为了避免行锁升级为表锁,可以采取以下措施:

1. 优化查询

  • 避免全表扫描:尽量使用索引进行查询,避免全表扫描。全表扫描会导致InnoDB将行锁升级为表锁。

    • 例如,使用WHERE子句来限制查询的范围:
    SELECT * FROM my_table WHERE id = 123; -- 使用索引
  • 分页查询:对于大数据量的查询,使用分页查询(如LIMIT)来减少锁定的行数。

    • 例如:
    SELECT * FROM my_table ORDER BY id LIMIT 100;

2. 减少锁的持有时间

  • 缩短事务时间:尽量缩短事务的执行时间,减少锁的持有时间。

    • 例如,将长时间的操作拆分为多个小事务:
    START TRANSACTION;
    UPDATE my_table SET column1 = 'value1' WHERE id = 123;
    COMMIT;
  • 批量操作:对于批量操作,尽量减少单个事务的操作量。

    • 例如,将批量插入操作拆分为多个小批次:
    START TRANSACTION;
    INSERT INTO my_table (column1, column2) VALUES ('value1', 'value2');
    COMMIT;

3. 使用较低的隔离级别

  • 降低隔离级别:使用较低的事务隔离级别(如READ COMMITTED)可以减少锁的持有时间,从而降低行锁升级为表锁的可能性。

    • 例如:
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

4. 合理使用锁

  • 显式锁:在必要时使用显式锁(如SELECT ... FOR UPDATE),而不是隐式锁。

    • 例如:
    SELECT * FROM my_table WHERE id = 123 FOR UPDATE;
  • 避免不必要的锁:尽量避免对不需要锁定的行进行锁定操作。

    • 例如,对于只读操作,使用SELECT ... LOCK IN SHARE MODE而不是SELECT ... FOR UPDATE

5. 监控和优化

  • 监控锁情况:使用MySQL的监控工具(如SHOW ENGINE INNODB STATUS)来监控锁的使用情况,及时发现和解决锁冲突问题。

    • 例如:
    SHOW ENGINE INNODB STATUS;
  • 优化表结构:合理设计表结构,使用适当的索引,减少锁冲突的可能性。

    • 例如,为频繁更新的列创建索引:
    CREATE INDEX idx_column1 ON my_table(column1);

MySQL减少锁等待的方式

在MySQL中,减少锁等待是提高数据库并发性能的关键。锁等待是指一个事务在等待另一个事务释放锁资源时所经历的时间。通过以下几种方式,可以有效减少锁等待,提高系统的并发性能:

1. 优化查询

1.1 使用索引

  • 索引优化:确保查询中使用的列上有适当的索引。索引可以显著减少查询的执行时间,从而减少锁的持有时间。

    • 例如,为经常查询的列创建索引:
    CREATE INDEX idx_column1 ON my_table(column1);
  • 覆盖索引:使用覆盖索引(Covering Index),即索引包含了查询所需的所有列,从而避免回表操作,减少锁的持有时间。

    • 例如:
    SELECT column1, column2 FROM my_table WHERE column1 = 'value';

1.2 避免全表扫描

  • 避免全表扫描:全表扫描会导致InnoDB将行锁升级为表锁,从而增加锁等待时间。尽量使用WHERE子句来限制查询的范围。

    • 例如:
    SELECT * FROM my_table WHERE id = 123; -- 使用索引

2. 减少锁的持有时间

2.1 缩短事务时间

  • 事务拆分:尽量将长时间的事务拆分为多个小事务,减少锁的持有时间。

    • 例如:
    START TRANSACTION;
    UPDATE my_table SET column1 = 'value1' WHERE id = 123;
    COMMIT;
  • 批量操作:对于批量操作,尽量减少单个事务的操作量。

    • 例如:
    START TRANSACTION;
    INSERT INTO my_table (column1, column2) VALUES ('value1', 'value2');
    COMMIT;

2.2 使用较低的隔离级别

  • 降低隔离级别:使用较低的事务隔离级别(如READ COMMITTED)可以减少锁的持有时间,从而降低锁等待的可能性。

    • 例如:
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

3. 合理使用锁

3.1 显式锁

  • 显式锁:在必要时使用显式锁(如SELECT ... FOR UPDATE),而不是隐式锁。

    • 例如:
    SELECT * FROM my_table WHERE id = 123 FOR UPDATE;
  • 避免不必要的锁:尽量避免对不需要锁定的行进行锁定操作。

    • 例如,对于只读操作,使用SELECT ... LOCK IN SHARE MODE而不是SELECT ... FOR UPDATE

3.2 锁超时设置

  • 锁超时:设置锁等待的超时时间,如果一个事务在等待锁的时间超过了设定的超时时间,则自动放弃该锁请求,并回滚事务。

    • 例如:
    SET innodb_lock_wait_timeout = 30; -- 设置锁等待超时时间为30秒

4. 监控和优化

4.1 监控锁情况

  • 监控工具:使用MySQL的监控工具(如SHOW ENGINE INNODB STATUS)来监控锁的使用情况,及时发现和解决锁冲突问题。

    • 例如:
    SHOW ENGINE INNODB STATUS;
  • 死锁日志:记录死锁信息,分析死锁的根本原因,并进行优化。

    • 例如:
    SHOW ENGINE INNODB STATUS;

4.2 优化表结构

  • 合理设计表结构:合理设计表结构,使用适当的索引,减少锁冲突的可能性。

    • 例如,为频繁更新的列创建索引:
    CREATE INDEX idx_column1 ON my_table(column1);

5. 并发控制

5.1 乐观锁

  • 乐观锁:使用乐观锁机制,假设数据在大多数情况下不会发生冲突,从而减少锁的使用。

    • 例如,使用版本号或时间戳来实现乐观锁:
    UPDATE my_table SET column1 = 'value1', version = version + 1 WHERE id = 123 AND version = 1;

5.2 悲观锁

  • 悲观锁:在必要时使用悲观锁机制,确保数据的一致性。

    • 例如,使用SELECT ... FOR UPDATE来锁定行:
    SELECT * FROM my_table WHERE id = 123 FOR UPDATE;

项目中的kafka限流是如何做的

kafka进行限流如何保证异步结果能够被获取(由调用之间使用长连接还是短连接引申出来的)

一亿条数据进行清洗,多线程如何操作

欢迎来到我的 ChatGPT 中转站,极具性价比,为付费不方便的朋友提供便利,有需求的可以添加左侧 QQ 二维码,另外,邀请新用户能获取余额哦!最后说一句,那啥:请自觉遵守《生成式人工智能服务管理暂行办法》。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇