Bootstrap

某m大厂面经1

mybatisplus有什么优点

mybatisplus如何进行多表查询

项目中有哪些表

xxl-job如何实现分布式定时任务

feign和nacos之间怎么交互

springboot服务启动流程

怎么用jar包启动类

maven打包的形式

dependence和dependencemanagement区别

redis应用场景

redisson怎么实现

px ex命令

linux如何查找文件的最后几行

vim常用命令

redis单线程如何实现高可用

请求过多单线程如何解决

Java反射

重载和重写的区别,结合项目举例

算法(讲思路):环形链表如何找到环的起点

项目中有没有遇到过数据库死锁

怎么人为设计一个死锁

rabbitmq在coding上有什么特点

这是一份关于不同技术和工具的问题列表。下面我会一一回答这些问题,并简要介绍相关的概念和实现方法。


1. MyBatis-Plus 有什么优点?

MyBatis-Plus 是对 MyBatis 的增强,它提供了许多便捷的功能来简化数据库操作,常见优点包括:

  • 简化 CRUD 操作:MyBatis-Plus 提供了通用的 BaseMapper,包括常见的增、删、改、查方法,避免了大量的 SQL 编写。
  • 无侵入性:它是对 MyBatis 的增强,MyBatis 代码可以继续使用,无需重构原有代码。
  • 性能优化:支持分页、SQL 解析、乐观锁等,且能够自动根据实体类生成 SQL。
  • 自动填充:可以自动填充字段,如创建时间、修改时间等。
  • 支持代码生成器:可以自动生成实体类、Mapper、Service、Controller 等代码,提升开发效率。

2. MyBatis-Plus 如何进行多表查询?

MyBatis-Plus 支持自定义 SQL,但它本身并没有提供像 JPA 或 Hibernate 那样的自动多表查询功能。可以通过如下方式进行多表查询:

  • XML 配置:通过 XML 自定义 SQL 语句,支持一对多、多对多等复杂查询。
  • Wrapper 条件构造器:结合 QueryWrapperLambdaQueryWrapper 进行多条件查询,虽然不直接支持多表联接,但可以通过手动书写 SQL 实现。

例如,使用 @Select 注解的方式来手动编写多表 SQL:

@Select("SELECT * FROM user u INNER JOIN order o ON u.id = o.user_id WHERE u.age > 18")
List<UserOrder> selectUserOrders();

3. 项目中有哪些表?

这类问题通常是询问项目中的数据库表结构。在项目中,可以通过以下方式查看或列出表:

  • 数据库 ER 图:生成数据库的实体关系图,常见工具如 MySQL WorkbenchNavicatDBeaver 等。
  • JPA 或 MyBatis 映射:查看数据库与实体类之间的映射关系,查看项目中定义的实体类和其对应的表。

4. XXL-JOB 如何实现分布式定时任务?

XXL-JOB 是一个轻量级的分布式任务调度框架,支持定时任务的分布式执行。它通过以下方式实现分布式定时任务:

  • 任务调度中心:XXL-JOB 的核心是调度中心,负责调度任务和管理任务执行状态。
  • 执行器:执行器是实际运行任务的地方,可以在多个机器上部署执行器节点,任务会根据负载均衡的方式分发给不同的执行器。
  • 任务调度和负载均衡:任务调度中心根据配置的 cron 表达式进行定时任务调度,同时通过一致性哈希或随机方式将任务分配给多个执行器。

5. Feign 和 Nacos 之间怎么交互?

  • Feign:是一个声明式的 Web 服务客户端,可以通过注解的方式发起 HTTP 请求,简化了服务间的调用。
  • Nacos:是一个开源的动态服务发现和配置管理平台,提供了服务注册与发现的功能。

Feign 和 Nacos 的交互方式通常是:Feign 通过使用 Spring Cloud 的负载均衡与服务发现功能来调用 Nacos 注册中心上的服务。常见配置方式如下:

  • application.yml 中配置 Nacos 作为服务发现的中心:
    spring:
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848
    
  • Feign 客户端会自动从 Nacos 获取服务信息并进行调用。

6. SpringBoot 服务启动流程

Spring Boot 的启动流程大致如下:

  1. 启动类加载:Spring Boot 应用程序会从 @SpringBootApplication 注解的主类开始。
  2. 创建 Spring 容器:Spring Boot 会自动创建 ApplicationContext(容器)。
  3. 自动配置:Spring Boot 自动配置相关组件(如数据源、Web 环境等),根据 application.propertiesapplication.yml 配置文件初始化。
  4. 启动 Tomcat 或嵌入式服务器:Spring Boot 默认使用嵌入式的 Tomcat 启动 Web 环境。
  5. 初始化 Bean:加载所有被 @Component@Service 等注解的 Bean。

7. 怎么用 JAR 包启动类?

要通过 JAR 包启动 Spring Boot 项目,可以使用以下命令:

java -jar your-app.jar

确保在 pom.xml 文件中配置了 Spring Boot 插件:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

8. Maven 打包的形式

Maven 支持多种打包形式,常见的有:

  • JAR:适用于 Java 项目,使用 mvn clean package 打包为一个可执行的 JAR 文件。
  • WAR:适用于 Web 项目,将项目打包为一个 WAR 文件,适用于传统的 Servlet 容器部署。
  • POM:打包一个 POM 文件,用于管理项目依赖。

9. dependency 和 dependencyManagement 区别

  • dependency:在 dependencies 中定义的依赖直接包含到项目中,用于编译、运行。
  • dependencyManagement:用于管理依赖的版本。它不直接引入依赖,只是定义了版本号,具体依赖会在 dependencies 中引用。

10. Redis 应用场景

Redis 常用于以下场景:

  • 缓存:用作高性能的缓存系统,减少数据库访问压力。
  • 消息队列:Redis 的列表和发布/订阅模型可用于实现消息队列。
  • 会话存储:用作分布式会话存储,尤其是在微服务架构中。
  • 计数器:可以用来实现计数器或限流功能。

11. Redisson 怎么实现

Redisson 是一个基于 Redis 的 Java 客户端,提供了更高级别的抽象,支持分布式锁、分布式集合、分布式队列等功能。它通过 Redis 实现了高可用、分布式数据结构等功能。

12. PX EX 命令

  • PX:表示过期时间,单位为毫秒。
  • EX:表示过期时间,单位为秒。

这些命令一般用于设置键的过期时间。例如:

SET mykey value EX 10  # 10秒后过期
SET mykey value PX 1000  # 1000毫秒后过期

13. Linux 如何查找文件的最后几行

可以使用 tail 命令查看文件的最后几行:

tail -n 10 filename  # 查看文件的最后10行

14. Vim 常用命令

  • i:进入插入模式。
  • :w:保存文件。
  • :q:退出 Vim。
  • :wq:保存并退出。
  • dd:删除当前行。
  • yy:复制当前行。
  • p:粘贴内容。

15. Redis 单线程如何实现高可用

尽管 Redis 是单线程的,但它通过以下方式实现高可用:

  • 主从复制:通过主节点和从节点复制数据,提高读取性能和容错能力。
  • 哨兵模式:使用 Redis Sentinel 来监控主节点,并在主节点故障时自动切换到从节点,确保高可用性。

16. 请求过多单线程如何解决

如果单线程处理请求的速度不够快,可以考虑:

  • 增加线程池:通过多线程来并发处理请求。
  • 队列:使用队列将请求排队处理。
  • 异步处理:将请求处理改为异步执行,提升吞吐量。

17. Java 反射

反射是 Java 提供的一种机制,可以在运行时获取类的信息、创建对象、调用方法等。常见用法包括:

  • 获取类的构造方法、方法、字段等。
  • 动态创建对象、调用方法。

例如:

Class<?> clazz = Class.forName("java.lang.String");
Method method = clazz.getMethod("substring", int.class, int.class);
String result = (String) method.invoke("hello", 1, 3);  // "el"

18. 重载和重写的区别,结合项目举例

  • 重载(Overloading):方法名相同,但参数列表不同。

重载和重写的区别,结合项目举例

算法(讲思路):环形链表如何找到环的起点

项目中有没有遇到过数据库死锁

怎么人为设计一个死锁

rabbitmq在coding上有什么特点

1. 重载和重写的区别,结合项目举例

  • 重载(Overloading):是指在同一个类中,方法名相同,但参数类型、数量或顺序不同。重载的目的是允许使用不同参数来调用同一个方法。

    特点

    • 方法名相同,但参数不同。
    • 可以有不同的返回类型、访问修饰符等,但参数必须不同
    • 发生在编译时,属于静态多态。

    示例
    假设有一个计算器类 Calculator,其方法通过不同的参数类型进行重载:

    public class Calculator {
        public int add(int a, int b) {
            return a + b;
        }
    
        public double add(double a, double b) {
            return a + b;
        }
    
        public int add(int a, int b, int c) {
            return a + b + c;
        }
    }
    

    这里有三个 add 方法,分别接受不同的参数类型和数量。这是方法重载的一个例子。

  • 重写(Overriding):是指子类重新定义父类的方法,并且保持方法签名一致(方法名、返回类型、参数列表完全相同)。重写的目的是为了改变父类方法的实现,以便适应子类的需要。

    特点

    • 方法名、参数列表、返回类型必须相同。
    • 方法的实现不同,子类会提供新的实现。
    • 发生在运行时,属于动态多态。

    示例
    假设有一个动物类 Animal 和一个子类 DogDog 重写了 Animal 中的 makeSound 方法:

    public class Animal {
        public void makeSound() {
            System.out.println("Animal makes sound");
        }
    }
    
    public class Dog extends Animal {
        @Override
        public void makeSound() {
            System.out.println("Dog barks");
        }
    }
    

    在这个例子中,Dog 重写了 Animal 类中的 makeSound 方法。当创建 Dog 的对象并调用 makeSound() 方法时,输出的是 “Dog barks”,而不是父类中的 “Animal makes sound”。

总结

  • 重载:方法名相同,参数不同,发生在同一个类中,属于静态绑定。
  • 重写:方法名、参数完全相同,在子类中重新定义父类方法,属于动态绑定。

2. 算法(讲思路):环形链表如何找到环的起点

在环形链表中,可能存在一个环,通常可以通过 快慢指针(Floyd’s Cycle-Finding Algorithm)来检测环,并找出环的起点。

思路
  1. 检测环

    • 使用两个指针 slowfast,初始时 slow 每次移动一步,fast 每次移动两步。如果链表存在环,那么 slowfast 指针一定会相遇。
  2. 找到环的入口

    • slowfast 相遇时,令 slow 回到链表的起点,然后 slowfast 都每次移动一步,当它们再次相遇时,就是环的起点。
代码实现
public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public ListNode detectCycle(ListNode head) {
    if (head == null || head.next == null) return null;
    
    ListNode slow = head, fast = head;
    
    // Phase 1: Detect if there is a cycle
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
        
        if (slow == fast) {  // Cycle detected
            // Phase 2: Find the start of the cycle
            slow = head;
            while (slow != fast) {
                slow = slow.next;
                fast = fast.next;
            }
            return slow;  // The node where the cycle begins
        }
    }
    
    return null;  // No cycle
}

3. 项目中有没有遇到过数据库死锁

数据库死锁是指两个或更多的数据库事务互相等待对方的锁,从而导致程序无法继续执行。在实际项目中,死锁通常发生在多个事务并发操作时,特别是当事务的执行顺序导致互相等待时。

举例

在一个订单管理系统中,假设有两个表 ordersproducts,当两个事务分别尝试更新这些表时,可能会发生死锁:

  • 事务 A 锁住 orders 表中的某个记录,然后尝试更新 products 表。
  • 事务 B 锁住 products 表中的某个记录,然后尝试更新 orders 表。

如果事务 A 和 B 相互等待对方释放锁,就会导致死锁。

4. 怎么人为设计一个死锁

人为设计一个死锁可以通过以下方式:

  • 使用两个线程分别持有对两个不同资源的锁,并且互相等待对方释放资源。

示例代码

public class DeadlockExample {

    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("Thread 1: Holding lock 1...");
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                System.out.println("Thread 1: Waiting for lock 2...");
                synchronized (lock2) {
                    System.out.println("Thread 1: Acquired lock 2.");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock2) {
                System.out.println("Thread 2: Holding lock 2...");
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                System.out.println("Thread 2: Waiting for lock 1...");
                synchronized (lock1) {
                    System.out.println("Thread 2: Acquired lock 1.");
                }
            }
        });

        thread1.start();
        thread2.start();
    }
}

在这个例子中,Thread 1Thread 2 分别持有不同的锁,并等待对方的锁,从而形成死锁。

5. RabbitMQ 在 Coding 上有什么特点

RabbitMQ 是一个流行的开源消息队列,它的特点和优势在于以下几个方面:

  • 高可靠性:RabbitMQ 支持持久化消息,确保消息不会丢失。
  • 灵活的路由机制:支持多种消息路由模式(如点对点、发布/订阅等)。
  • 支持多个协议:RabbitMQ 支持 AMQP 协议,并且还可以支持 MQTT、STOMP 等协议。
  • 高可扩展性:可以通过集群和镜像队列来实现高可用和负载均衡。
  • 异步消息处理:能够在处理大流量时异步处理消息,减轻系统压力。
常见应用场景
  • 异步任务处理:将耗时操作(如发送邮件、处理图片)异步化,提升系统响应速度。
  • 分布式系统通信:在多个微服务之间传递消息。
  • 消息通知系统:处理用户通知、短信、邮件等消息通知。

RabbitMQ 适用于需要可靠性和高可扩展性的系统,特别是在处理大规模异步消息时。

;