• 北京中冶赛迪面试总结


    自我介绍+项目介绍

    目录

    1.介绍一下mysql中的索引?

    2.在 MySQL 中,如果您有一个 (a, b, c) 的联合索引,查询条件仅包含 a 和 c 而没有 b索引的生效情况?

    3.mysql 锁的类型?

    4.表中的数据重复删除怎么实现?

    方法1:使用子查询

    方法2:使用JOIN

    方法3:使用ROW_NUMBER()

    5.HashMap的遍历方式?

    6.null 在mysql中用什么处理怎么存储?

    7.什么情况下会垃圾回收?

    8.创建线程的方式?

    9.redis 有原子性 和 隔离性吗?

    原子性(Atomicity)

    隔离性(Isolation)

    持久性(Durability)

    总结

    10.redis常用五大类型?

    11.redis 键的淘汰策略?

    12.SpringBoot核心注解有哪些?

    13.Integer a = 321;  Integer b = 321; 用==比较会返回什么?

    14.分库分表的键 怎么设置?

    15.介绍一下Aop?

    16.订单状态值很多,流转时用if else不太方便,有什么解决方案?


    1.介绍一下mysql中的索引?

    索引是数据库表中一列或多列的值存储的数据结构,通常是 B+ 树(B-Tree 的变种),它允许快速查找表中的行。

    • 主键索引:唯一且不允许空值,每个表只能有一个主键索引。
    • 唯一索引:唯一但允许有空值,可以有多个。
    • 普通索引:没有任何唯一性或非空限制。
    • 全文索引:用于对文本内容进行全文搜索。
    • 空间索引:用于地理空间数据类型,以优化空间查询。
    • 合适的列:为经常用于搜索条件、连接和排序的列创建索引。
    • 索引覆盖:如果一个查询只需要访问索引中的列,那么这个索引被称为覆盖索引,它可以直接用于查询结果,而不需要访问表数据。
    • 复合索引:当经常需要根据多个列进行搜索时,可以考虑创建复合索引。

           应该尽量避免违反最左前缀法则,已经其他使索引失效的场景,用慢查询日志以及explain可以分析慢sql,作出进一步优化。

    2.在 MySQL 中,如果您有一个 (a, b, c)联合索引,查询条件仅包含 ac 而没有 b索引的生效情况?

    1. 索引最左前缀规则:MySQL 联合索引遵循最左前缀规则,这意味着查询时必须包含索引最左边的列才能使用索引。所以,如果您的查询包含了 a,索引就可以被使用。

    2. 索引选择性:如果 a 的选择性很高(不同的值很多),即使没有包含 b,查询也可能因为 a 的选择性而受益。

    3.mysql 锁的类型?

    1. 共享锁(Shared Locks)

    共享锁,也称为读锁,允许多个事务同时读取同一资源,但不能修改它。当一个事务对数据加上共享锁后,其他事务可以继续加共享锁进行读取,但不能加排它锁进行写入。

    2. 排它锁(Exclusive Locks)

    排它锁,也称为写锁,允许事务修改数据。当一个事务对数据加上排它锁后,其他事务不能对该数据加任何类型的锁。

    3. 行级锁(Row-level Locks)

    MySQL 支持行级锁定,这是最细粒度的锁,只锁定相关的行记录。InnoDB 存储引擎使用行级锁来实现事务的隔离性。

    4. 表级锁(Table-level Locks)

    表级锁锁定整个表,MyISAM 和其他一些存储引擎使用表级锁。由于锁定了整个表,所以并发性能不如行级锁。

    5. 间隙锁(Gap Locks)

    间隙锁是一种行级锁,它锁定一个范围内的间隙,但不包括记录本身。间隙锁用于防止其他事务插入间隙中的新记录,以维护事务的可重复读性。

    6. 临键锁(Next-Key Locks)

    临键锁是 InnoDB 存储引擎中的一种锁,它结合了行锁和间隙锁。临键锁锁定一个记录以及记录前面的间隙。

    7. 意向锁(Intention Locks)

    意向锁是一种表明事务想要在更细粒度上加锁的锁。它们用于在锁定层次结构中向上升级,从行级到表级。意向锁分为意向共享锁(Intention Shared Lock)和意向排它锁(Intention Exclusive Lock)。

    8. 自增锁(AUTO-INC Locks)

    在 InnoDB 中,自增锁用于管理表的自增字段。当插入新记录时,InnoDB 会请求一个自增锁,以确保自增字段的值是唯一的。

    9. 全局锁(Global Locks)

    全局锁是 MySQL 中最高层次的锁,它锁定整个数据库系统。这种锁通常用于复制和恢复操作。

    10. 元数据锁(Metadata Locks)

    元数据锁用于控制对数据库结构的更改,如添加或删除表。

    11. 死锁(Deadlocks)

    死锁发生在两个或多个事务相互等待对方持有的锁,导致无法继续执行。

    4.表中的数据重复删除怎么实现?

    方法1:使用子查询

    假设你有一个表my_table,其中包含字段id(假设是主键)和column1,你想删除column1字段的重复数据,保留每个重复组的第一个记录。

    1. DELETE FROM my_table
    2. WHERE id NOT IN (
    3. SELECT MIN(id)
    4. FROM my_table
    5. GROUP BY column1
    6. );

    这个查询首先找出每个column1值的最小id,然后删除不在这些最小id列表中的所有记录。

    方法2:使用JOIN

    使用LEFT JOIN来保留重复数据中的第一条记录。

    1. DELETE my_table
    2. FROM my_table
    3. LEFT JOIN (
    4. SELECT MIN(id) as min_id
    5. FROM my_table
    6. GROUP BY column1
    7. ) AS subquery
    8. ON my_table.id = subquery.min_id
    9. WHERE my_table.id > subquery.min_id;

    这个查询将my_table与一个子查询进行左连接,子查询返回每个column1值的最小id。然后,它删除连接后my_tableid大于最小id的所有记录。

    方法3:使用ROW_NUMBER()

    如果你使用的数据库支持窗口函数(如SQL Server、PostgreSQL、MySQL 8.0+等),可以使用ROW_NUMBER()来为每个重复组分配一个序号,然后删除序号大于1的记录。

    1. DELETE FROM my_table
    2. WHERE row_num > 1;y.min_id;

    首先,你需要创建一个临时表或使用WITH语句来确定每个记录的序号:

    1. WITH RankedRecords AS (
    2. SELECT *, ROW_NUMBER() OVER (PARTITION BY column1 ORDER BY id) AS row_num
    3. FROM my_table
    4. )
    5. DELETE FROM RankedRecords
    6. WHERE row_num > 1;

    在这个例子中,ROW_NUMBER()为每个column1值的分组分配一个序号,序号从1开始,并且按id排序。然后,删除序号大于1的所有记录。

    5.HashMap的遍历方式?

    HashMap 是 Java 中实现的一个基于哈希表的 Map 接口,它存储键值对(key-value pairs)。在 Java 中,有几种不同的方式可以遍历 HashMap

    1. 使用 keySet() 方法

    这是最常用的遍历 HashMap 的方法。首先获取所有键的集合,然后遍历这个集合,并使用每个键来获取对应的值。

    1. HashMap map = new HashMap<>();
    2. // 假设map已经初始化并填充了数据
    3. for (KeyType key : map.keySet()) {
    4. ValueType value = map.get(key);
    5. // 处理键和值
    6. }

    2. 使用 entrySet() 方法

    entrySet() 方法返回的是一个 Set 集合,集合中的元素是 Map.Entry 对象。每个 Map.Entry 对象都包含一个键和一个值。

    1. for (Map.Entry entry : map.entrySet()) {
    2. KeyType key = entry.getKey();
    3. ValueType value = entry.getValue();
    4. // 处理键和值
    5. }

    3. 使用 Java 8 的 forEach() 方法

    从 Java 8 开始,Map 接口提供了 forEach() 方法,它接受一个 BiConsumer 函数式接口作为参数,可以对每个键值对执行操作。

    1. map.forEach((key, value) -> {
    2. // 处理键和值
    3. });

    4. 使用 values() 方法

    values() 方法返回的是一个 Collection,包含 HashMap 中所有的值。通常,这种方法不推荐使用,因为如果你需要同时访问键和值,它就不如 keySet()entrySet() 方法高效。

    1. Collection values = map.values();
    2. for (ValueType value : values) {
    3. // 仅处理值,如果需要键,需要再次查询
    4. }

    5. 使用 Java 8 的 Stream API

    从 Java 8 开始,可以使用 stream() 方法来获取 HashMap 的流,并进行更复杂的操作。

    1. map.entrySet().stream()
    2. .forEach(entry -> {
    3. KeyType key = entry.getKey();
    4. ValueType value = entry.getValue();
    5. // 处理键和值
    6. });

    6. 使用迭代器(Iterator)

    可以使用 iterator() 方法获取迭代器,然后使用迭代器遍历 HashMap

    1. Iterator> iterator = map.entrySet().iterator();
    2. while (iterator.hasNext()) {
    3. Map.Entry entry = iterator.next();
    4. KeyType key = entry.getKey();
    5. ValueType value = entry.getValue();
    6. // 处理键和值
    7. }

    每种遍历方式都有其适用场景,选择哪一种取决于你的具体需求。例如,如果你需要修改 HashMap,那么使用迭代器可能是更好的选择。如果你只是需要读取数据,那么 keySet()entrySet()forEach() 方法可能更简单、更直观。

    6.null 在mysql中用什么处理怎么存储?

    在 MySQL 中,NULL 不是一个数据类型,而是一个特殊的标记,用来表示字段中没有数据。在 SQL 中,NULL 用于表示未知或缺失的数据值。

    每个数据类型都可以存储 NULL 值,例如:

    • INT:整数类型,可以存储 NULL 值。
    • VARCHAR:可变长度的字符串类型,可以存储 NULL 值。
    • DATE:日期类型,可以存储 NULL 值。
    • FLOAT:浮点数类型,可以存储 NULL 值。
    • 等等...

    NULL 值在 SQL 中的处理与其他值不同,例如:

    • NULL 与任何值(包括另一个 NULL)的比较总是产生 NULL 结果,这意味着比较是不确定的。
    • 在使用 COUNT() 函数时,默认情况下 NULL 值不会被计入总数。
    • 在使用 ORDER BY 子句时,NULL 值通常会被排序在结果集的开始或结束位置,这取决于具体的 SQL 配置和版本。

    因此,设计数据库时,需要根据数据模型和业务需求来决定哪些字段可以存储 NULL 值,以及如何处理这些 NULL 值。

    7.什么情况下会垃圾回收?

    垃圾回收(Garbage Collection, GC)通常在以下情况下触发:

    1. 内存分配请求时

      • 当应用程序尝试分配新对象,而内存不足时,垃圾回收器会被触发以释放内存。
    2. 内存使用达到阈值

      • 在一些垃圾回收系统中,内存使用达到特定阈值时会触发垃圾回收。
    3. 定时触发

      • 有些垃圾回收器会根据设定的时间间隔定期执行,以清理内存。
    4. 系统空闲时

      • 在一些系统中,垃圾回收可能在系统空闲时自动执行,以优化内存使用。
    5. 显式调用

      • 在某些编程语言中,开发者可以通过特定的方法或函数显式请求执行垃圾回收。
    6. 内存碎片整理

      • 当内存分配和回收导致内存碎片化时,垃圾回收器可能会被触发以整理内存。
    7. 新生代到老年代的晋升

      • 在使用分代垃圾回收策略的系统中,对象在新生代存活一定次数后会被晋升到老年代,这可能会触发老年代的垃圾回收。
    8. 堆空间不足

      • 当整个堆空间不足时,垃圾回收器会被触发以尝试释放更多内存。
    9. 外部触发

      • 某些外部事件或条件(如操作系统的内存压力)也可能触发垃圾回收。
    10. 特定事件

      • 在一些系统中,特定的事件(如类加载器卸载)可能会触发垃圾回收。

    8.创建线程的方式?

    1. 继承 Thread 类

    2. 实现 Runnable 接口

    3. 使用 Callable 和 Future

    4. 使用 Executors 框架

    9.redis 有原子性 和 隔离性吗?

    原子性(Atomicity)

    在 Redis 中,单个命令的执行是原子性的。这意味着当一个命令被执行时,它要么完全执行,要么完全不执行,不会出现执行到一半的情况。Redis 通过单线程来处理命令,确保了命令执行的原子性。

    然而,如果一个操作涉及多个命令,Redis 默认情况下并不保证这些命令作为一个整体的原子性。为了实现多个命令的原子性,Redis 提供了以下两种机制:

    1. 事务(Transactions):通过 MULTIEXECWATCH 和 DISCARD 命令,Redis 允许客户端将多个命令打包在一起执行,要么全部成功,要么全部失败。
    2. Lua 脚本(Lua scripting):Redis 支持在服务器端执行 Lua 脚本,脚本中的命令会作为一个整体执行,保证原子性。

    隔离性(Isolation)

    Redis 默认运行在单线程模式下,这意味着在任何给定时间点,只有一个命令被执行。因此,Redis 自然地提供了一定程度的隔离性,因为不会有多个命令同时干扰彼此的执行。

    但是,Redis 的隔离性与传统数据库的隔离级别(如读已提交、可重复读、可串行化)不同。在 Redis 中:

    • 无锁(Lock-free):Redis 的操作不需要使用锁,因为单线程模型保证了不会有并发冲突。
    • 并发控制:虽然 Redis 单线程模型提供了隔离性,但在高并发环境下,客户端可能会遇到竞态条件。Redis 提供了一些机制来控制并发,如使用 WATCH 命令监视键值的变化,以及使用事务来保证操作的一致性。

    持久性(Durability)

    Redis 还提供了持久性选项,通过 RDB 快照和 AOF 日志记录,确保数据在系统故障后能够恢复。

    总结

    Redis 的原子性和隔离性与传统的关系型数据库不同,它通过单线程模型和事务机制来保证操作的原子性,并通过单线程执行来自然地提供隔离性。然而,Redis 不提供传统数据库中的严格隔离级别,所以在设计系统时需要考虑到这一点,并根据需要使用 Redis 提供的机制来保证数据的一致性和完整性。

    10.redis常用五大类型?

    1. 字符串(Strings)

      • 基本的数据类型,用于存储简单的字符串数据。
      • 可以执行的操作包括设置(SET)、获取(GET)、删除(DEL)等。
    2. 列表(Lists)

      • 列表是简单的字符串列表,按照插入顺序排序。
      • 可以执行的操作包括左推(LPUSH/RPUSH)、右弹(LPOP/RPOP)、获取列表长度(LLEN)等。
    3. 集合(Sets)

      • 集合是一个无序集合,可以存储不重复的字符串元素。
      • 可以执行的操作包括添加(SADD)、移除(SREM)、检查成员(SISMEMBER)等。
    4. 有序集合(Sorted Sets)

      • 类似于集合,但是每个元素都有一个分数(score)与之关联,并且按照分数进行排序。
      • 可以执行的操作包括添加(ZADD)、获取排名(ZRANK/ZREVRANK)、获取范围(ZRANGE/ZREVRANGE)等。
    5. 哈希(Hashes)

      • 哈希是一个键值对集合,其中每个键和值都是字符串。
      • 可以执行的操作包括设置字段(HSET)、获取字段(HGET)、删除字段(HDEL)等。

    11.redis 键的淘汰策略?

    1. noeviction:这是默认的淘汰策略。当内存达到限制时,Redis 将拒绝所有会修改数据集的命令(例如 SET、LPUSH 等),但不会自动删除任何键。

    2. allkeys-lru:在所有键中,根据最近最少使用(Least Recently Used)算法淘汰数据。

    3. volatile-lru:在设置了过期时间的键中,根据 LRU 算法淘汰数据。

    4. allkeys-random:在所有键中随机选择一个键进行淘汰。

    5. volatile-random:在设置了过期时间的键中随机选择一个键进行淘汰。

    6. volatile-ttl:在设置了过期时间的键中,选择即将过期的键进行淘汰。

    12.SpringBoot核心注解有哪些?

    1. @SpringBootApplication

      • 组合注解,包含 @Configuration@EnableAutoConfiguration 和 @ComponentScan
      • 用于定义主应用程序类,指示 Spring Boot 应运行类路径扫描。
    2. @RestController

      • 组合注解,包含 @Controller 和 @ResponseBody
      • 用于定义 RESTful web 服务。
    3. @RequestMapping

      • 用于映射 HTTP 请求到控制器的处理方法。
      • 可以指定请求的路径、方法等。
    4. @GetMapping@PostMapping@PutMapping@DeleteMapping

      • 特定类型的 @RequestMapping,分别用于处理 GET、POST、PUT 和 DELETE 请求。
    5. @Autowired

      • 用于自动装配依赖注入的组件。
    6. @Service

      • 用于标记服务层的组件。
    7. @Repository

      • 用于标记数据访问层的组件,通常与数据库交互。
    8. @Component

      • 用于标记 Spring 管理的组件。
    9. @Configuration

      • 用于标记类包含 bean 的定义。
    10. @Bean

      • 用于在方法级别上声明一个 bean。
    11. @Value

      • 用于注入外部配置的值。
    12. @PropertySource

      • 用于加载属性文件。
    13. @EnableAutoConfiguration

      • 告诉 Spring Boot 根据添加的 jar 依赖自动配置项目。
    14. @ComponentScan

      • 用于指定 Spring 搜索组件、配置、服务等的包路径。
    15. @RestControllerAdvice

      • 用于定义全局异常处理、数据绑定或数据验证。
    16. @PathVariable

      • 用于将 URL 中的模板变量绑定到控制器处理方法的参数上。
    17. @RequestParam

      • 用于将请求参数映射到控制器处理方法的参数上。
    18. @RequestBody

      • 用于将 HTTP 请求的 body 绑定到控制器处理方法的参数上。
    19. @ResponseBody

      • 用于指示方法的返回值应该被作为 HTTP 响应的正文返回。
    20. @Profile

      • 用于指定组件的激活环境。
    21. @Async

      • 用于声明异步方法。
    22. @Scheduled

      • 用于声明定时任务。

    13.Integer a = 321;  Integer b = 321; 用==比较会返回什么?

    在 Java 中,Integer 类型的对象进行 == 比较时,比较的是它们在内存中的引用地址,而不是它们所封装的值。如果两个 Integer 对象是通过自动装箱(autoboxing)创建的,它们通常指向内存中的同一个缓存对象。Java 为每个整数值 -128 到 127 缓存了一个 Integer 对象,所以当你创建一个这个范围内的 Integer 对象时,实际上是从一个缓存中取得的。超过范围会返回false。

    14.分库分表的键 怎么设置?

    分库键(Shard Key)

    1. 业务无关性:选择与业务逻辑无关的字段作为分库键,以避免数据倾斜。

    2. 数据均匀性:选择能够使数据均匀分布的字段,例如用户ID、订单ID等。

    3. 查询模式:根据查询模式选择分库键,使得查询操作能够快速定位到特定的库。

    4. 范围分区:如果数据具有时间属性,可以选择时间字段作为分库键,实现时间范围分区。

    分表键(Partition Key)

    1. 数据量预估:根据数据增长趋势和表的大小预估,选择合适的字段进行分表。

    2. 访问模式:根据数据的访问模式,选择能够提高查询效率的字段作为分表键。

    3. 数据关联性:如果表之间存在关联关系,可以选择关联字段作为分表键,以保持数据的一致性。

    4. 复合分区:可以使用多个字段的组合作为分表键,实现复合分区策略。

    常见分库分表策略

    1. 哈希分区:使用哈希函数对分库/分表键进行哈希计算,根据哈希值将数据分配到不同的库或表。

    2. 范围分区:根据分库/分表键的数值范围进行分区,例如按年份、按ID范围等。

    3. 列表分区:将分库/分表键的值映射到一个预定义的列表中,根据列表中的顺序分配数据。

    4. 一致性哈希:使用一致性哈希算法分配数据,可以在增减节点时减少数据迁移。

    15.介绍一下Aop?

    AOP 的核心概念包括:

    1. 切面(Aspect):切面是一组横切关注点的模块化表示,它包括通知(Advice)、切点(Pointcut)、目标对象(Target Object)、代理(Proxy)等。

    2. 通知(Advice):通知是切面的一部分,它定义了何时以及如何增强目标对象的方法执行。通知可以在方法的执行前后、方法抛出异常时或在方法正常执行完成后执行。

    3. 切点(Pointcut):切点定义了一组特定的连接点(Join Point),这些连接点是程序执行过程中的特定位置,如方法的调用或异常的处理。

    4. 连接点(Join Point):连接点是程序执行过程中可以插入切面的特定位置,通常是方法的调用或处理程序的执行。

    5. 目标对象(Target Object):目标对象是被增强的对象,通常是应用程序中的业务逻辑类。

    6. 代理(Proxy):代理是目标对象的一个替代品,它在不修改目标对象的情况下,通过拦截方法调用来实现增强。

    16.订单状态值很多,流转时用if else不太方便,有什么解决方案?

    1. 策略模式(Strategy Pattern)

      • 策略模式定义了一系列算法,并将每一个算法封装起来,使它们可以互换。
      • 为订单的每个状态实现一个策略接口,订单对象根据当前状态使用相应的策略。
    2. 工厂模式(Factory Pattern)

      • 工厂模式用于创建对象,而不需要指定将要创建的具体类。
      • 为每个订单状态创建一个具体的工厂类,订单对象通过工厂来获取并执行状态相关的操作。

  • 相关阅读:
    2022牛客多校(五)
    通过修改metadata来修改一个图像中的label信息,进行扩充;obj_label: 一个数组,用于存储描述被检测对象类别的字符串
    亲测解决np.fromiter转换list的时候出现cannot create object arrays from iterator
    Redis 竟然能用 List 实现消息队列
    团建游戏---小泰山
    Vue框架总结(五、Vue配置代理)
    MybatisX插件 逆向工程
    WebRTC系列-网络传输之4Connection排序
    容器编排学习(五)卷的概述与存储卷管理
    每日小题打卡
  • 原文地址:https://blog.csdn.net/weixin_54673155/article/details/139343669