美团秋招一面面经

美团秋招一面面经

记录面试中遇到的问题,希望可以帮助到大家!

批处理批处理一个sql下的若干条sql,如何提高速度,如果要分片的话如何分片

1.使用数据库的批处理功能来执行多个 SQL 语句。这可以减少每个 SQL 语句的通信开销。JDBC 中的 addBatch()executeBatch() 方法可以用来执行批处理操作。

在程序开始时候设置禁止自动提交事务,将所有的sql语句添加到preparedStatement中,在程序执行过程中如果报错的话就回滚数据库事务。

    public static void main(String[] args) {
        String jdbcUrl = "jdbc:mysql://localhost:3306/your_database";
        String username = "your_username";
        String password = "your_password";

        try (Connection connection = DriverManager.getConnection(jdbcUrl, username, password)) {
            // 关闭自动提交,启用事务
            connection.setAutoCommit(false);

            String sql = "INSERT INTO your_table (column1, column2) VALUES (?, ?)";
            try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
                // 添加多条 SQL 语句到批处理中
                for (int i = 0; i < 1000; i++) {
                    preparedStatement.setInt(1, i);
                    preparedStatement.setString(2, "Value " + i);
                    preparedStatement.addBatch();
                }

                // 执行批处理
                int[] updateCounts = preparedStatement.executeBatch();

                // 提交事务
                connection.commit();
            } catch (SQLException e) {
                // 回滚事务
                connection.rollback();
                e.printStackTrace();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

2.使用多线程的方式处理,创建一个含有五个线程的线程池,逐个提交所有的sql语句,在线程的run方法中执行sql语句

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MultiThreadSQLExecution {
    public static void main(String[] args) {
        String jdbcUrl = "jdbc:mysql://localhost:3306/your_database";
        String username = "your_username";
        String password = "your_password";
        String sqlFilePath = "path_to_your_sql_file.sql";

        int numThreads = 5; // 指定线程数

        ExecutorService executorService = Executors.newFixedThreadPool(numThreads);

        try {
            Connection connection = DriverManager.getConnection(jdbcUrl, username, password);
            BufferedReader reader = new BufferedReader(new FileReader(sqlFilePath));
            String line;
            
            while ((line = reader.readLine()) != null) {
                // 提交每一条 SQL 语句给线程池
                executorService.submit(new SQLExecutionTask(connection, line));
            }

            // 等待所有线程完成
            executorService.shutdown();
            while (!executorService.isTerminated()) {
                Thread.sleep(100);
            }

            reader.close();
            connection.close();
        } catch (SQLException | IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    static class SQLExecutionTask implements Runnable {
        private Connection connection;
        private String sql;

        SQLExecutionTask(Connection connection, String sql) {
            this.connection = connection;
            this.sql = sql;
        }

        @Override
        public void run() {
            try (Statement statement = connection.createStatement()) {
                statement.execute(sql);
                System.out.println("Executed SQL: " + sql);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

网络错误码500,403

1xx - 信息性状态码(Informational)

  • 100 Continue:客户端应继续其请求。
  • 101 Switching Protocols:服务器要求客户端切换协议。

2xx - 成功状态码(Successful)

  • 200 OK:请求成功。
  • 201 Created:请求已创建新资源。
  • 204 No Content:请求已成功处理,但无响应体返回。

3xx - 重定向状态码(Redirection)

  • 301 Moved Permanently:请求的资源已永久移动到新位置。
  • 302 Found:请求的资源临时移动到新位置。
  • 304 Not Modified:资源未修改,可使用缓存。

4xx - 客户端错误状态码(Client Errors)

  • 400 Bad Request:请求错误,服务器不理解或无法处理请求。
  • 401 Unauthorized:需要身份验证才能访问资源。
  • 403 Forbidden:拒绝访问资源。
  • 404 Not Found:未找到请求的资源。

5xx - 服务器错误状态码(Server Errors)

  • 500 Internal Server Error:服务器遇到了意外错误。
  • 502 Bad Gateway:服务器作为网关或代理,从上游服务器接收无效响应。
  • 503 Service Unavailable:服务器当前无法处理请求,通常是暂时性的。
  • 504 Gateway Timeout:服务器作为网关或代理,未及时从上游服务器接收响应

算法:返回链表的倒数第n个值

使用双指针的方法,快指针比慢指针先走n步,然后快慢指针同时出发,最后快指针到达尾部时慢指针就是答案

public class ListNode {
    int val;
    ListNode next;

    ListNode(int val) {
        this.val = val;
    }
}

public int findNthFromEnd(ListNode head, int n) {
    ListNode slow = head;
    ListNode fast = head;

    // 将fast指针向前移动n个节点
    for (int i = 0; i < n; i++) {
        if (fast == null) {
            return -1; // 处理n大于链表长度的情况
        }
        fast = fast.next;
    }

    // 同时移动slow和fast指针,直到fast指针到达链表末尾
    while (fast != null) {
        slow = slow.next;
        fast = fast.next;
    }

    // 此时slow指向倒数第n个节点
    return slow.val;
}

post和get请求的区别,post的请求体有哪些内容?

HTTP(Hypertext Transfer Protocol)是一种用于传输数据的协议,它定义了客户端和服务器之间的通信规则。在HTTP中,GET和POST是两种常见的请求方法,它们在使用和请求体内容方面有一些区别。

GET 请求:

  1. 使用场景:GET请求用于从服务器获取数据,通常是获取资源、查询数据等,它是幂等的,即多次执行相同的GET请求应该具有相同的结果,不应该对服务器产生副作用。
  2. 请求体:GET请求通常不包含请求体,所有的参数和数据都会附加在URL的查询字符串中,以键值对的形式出现在URL后面,例如:http://example.com/resource?param1=value1¶m2=value2
  3. 数据传输:GET请求中的数据通过URL传输,因此在浏览器中可以直接看到,有长度限制,通常用于传输少量数据。
  4. 安全性:GET请求对数据的安全性要求较低,因为请求中的数据可以被轻松查看和修改,因此不适合用于敏感信息的传输。

POST 请求:

  1. 使用场景:POST请求通常用于向服务器提交数据,例如提交表单、上传文件等,它不是幂等的,即多次执行相同的POST请求可能会产生不同的结果,可能对服务器产生副作用。
  2. 请求体:POST请求包含一个请求体,请求体中存放着要传输的数据,可以是表单数据、JSON数据、XML数据等,没有数据长度限制。
  3. 数据传输:POST请求中的数据不会显示在URL中,而是放在请求体中,因此更适合传输大量数据,同时也更安全,因为数据不会直接暴露在URL中。
  4. 安全性:POST请求对数据的安全性要求较高,因为请求体中的数据不容易查看和修改,适合用于传输敏感信息。

深入理解

GET 和 POST都是http请求方式, 底层都是 TCP/IP协议;通常GET 产生一个 TCP 数据包;POST 产生两个 TCP 数据包(但firefox是发送一个数据包),对于 GET 方式的请求,浏览器会把 http header 和 data 一并发送出去,服务器响应 200

(返回数据)表示成功;而对于 POST,浏览器先发送 header,服务器响应 100, 浏览器再继续发送 data,服

务器响应 200 (返回数据)。

post请求可以通过url传输数据吗

POST请求通常将数据放在请求体中传输,而不是像GET请求那样将数据附加在URL中。这是POST请求的典型用法,因为POST请求通常用于传输较大量的数据,如表单提交、文件上传等。虽然理论上你可以将数据附加在URL中,但这不是POST请求的标准做法,而且由于URL长度限制,可能会导致数据丢失或不完整。

redis和mysql如何实现数据一致性

设置缓存过期时间是关键点

1、所有的写操作以数据库为准,只要到达缓存过期时间,缓存删除

2、如果后面还有读请求的话,就会从数据库中读取新值然后回填缓存

延时双删策略

在写库前后都进行redis.del(key)操作,并且设定合理的超时时间。

1、先删除缓存2、再写数据库3、休眠xxx毫秒(根据具体的业务时间来定)4、再次删除缓存

异步更新缓存(基于Mysql binlog的同步机制)

1、涉及到更新的数据操作,利用Mysql binlog 进行增量订阅消费

2、将消息发送到消息队列

3、通过消息队列消费将增量数据更新到Redis上

4、操作情况

如何设计redis缓存

  1. 数据存储策略:数据结构选择:根据数据的特性选择合适的Redis数据结构,如字符串、哈希表、列表、集合或有序集合。数据分区:如果需要存储大量数据,可以考虑将数据分区到多个Redis节点上,以便扩展存储容量和性能。
  2. 缓存更新策略:写入策略:确定何时将数据写入缓存。常见策略包括读写时更新、定期同步、发布/订阅模式等。数据同步:确保缓存中的数据与持久化数据源(如数据库)保持一致。可以采用双写、定期同步或消息队列等方式。
  3. 缓存失效策略:过期时间:为缓存设置适当的过期时间,以确保数据不会永远存在于缓存中。手动失效:在数据发生变化时,及时将缓存中的数据标记为失效,以便下次读取时从源数据获取。
  4. 缓存高可用性:主从复制:使用Redis的主从复制机制,确保数据的备份和高可用性。哨兵模式:使用Redis Sentinel来监控和管理Redis实例,以便在主节点故障时自动切换到备用节点。集群模式:使用Redis Cluster实现数据分片和高可用性。
  5. 缓存穿透和雪崩防止:布隆过滤器:使用布隆过滤器来防止缓存穿透,即查询不存在的数据。随机过期时间:在设置缓存失效时间时,添加随机性,以避免缓存雪崩。
  6. 安全性:限制外部访问:通过防火墙或其他手段限制Redis服务的外部访问,以保护数据安全。密码认证:设置Redis密码,确保只有授权用户可以访问Redis。
  7. 备份和恢复:定期备份:定期备份Redis数据,以应对数据丢失或损坏的情况。灾难恢复计划:制定灾难恢复计划,确保在发生严重故障时能够快速恢复数据。

linux为什么要设置用户态和内核态

在CPU指令中,有些指令是非常危险的,如果错用将导致系统崩溃,比如清内存、设置时钟等,所以CPU将指令分为特权指令和非特权指令。对于危险指令,只允许操作系统及其相关模块使用,普通应用程序只能使用不危险的指令。

  • Intel的CPU将特权等级分为4个级别:Ring0~Ring3,而Linux使用Ring3级别运行用户态,Ring0作为内核态。
  • 操作系统启动时对内存进行了划分,操作系统的数据都是存放于内核空间的,用户进程的数据是存放于用户空间的。处于用户态级别的程序只能访问用户空间,而处于内核态级别的程序可以访问用户空间和内核空间。
  • 当一个进程执行系统调用而陷入内核代码中执行时,我们就称进程处于内核态

cookie和session有什么区别

存储位置:Cookie:Cookie是存储在用户浏览器中的小型文本文件。每当用户访问一个网站时,服务器都可以向用户的浏览器发送一个或多个Cookie,然后浏览器将这些Cookie保存在用户的本地计算机上。Session:Session数据通常存储在服务器端。服务器会为每个会话(通常对应一个用户的一次访问会话)创建一个唯一的标识符,然后将相关数据存储在服务器的内存中或持久化到数据库中。

安全性:Cookie:Cookie存储在用户的浏览器中,因此可以被用户修改或删除。虽然可以使用加密技术增强Cookie的安全性,但仍然容易受到跨站脚本攻击(XSS)等攻击。Session:Session数据存储在服务器上,用户无法直接访问或修改。这使得Session通常比Cookie更安全,但服务器端的安全性仍然至关重要。

存储容量:Cookie:浏览器对Cookie的存储容量有限制,通常每个Cookie的大小不应超过几KB。这限制了Cookie可以存储的数据量。Session:服务器端的存储通常比较大,可以存储更多的数据,不受浏览器限制。

有效期:Cookie:可以设置Cookie的过期时间。可以是会话Cookie(浏览器关闭后失效)或持久Cookie(在一段时间后失效)。Session:会话数据通常在用户关闭浏览器时自动失效,但也可以通过设置过期时间来延长其有效期。

用途:Cookie:主要用于跟踪用户的身份、记录用户偏好设置、购物车信息等。它们通常用于客户端状态管理。Session:用于在服务器端维护用户的会话状态,通常用于身份验证、授权、购物车管理等服务器端状态管理。

跨页面传递:Cookie:可以在不同页面之间传递数据,因为它们存储在浏览器中,可以被不同页面的JavaScript代码读取。Session:Session数据通常存储在服务器上,可以在服务器上的不同页面之间共享,但需要通过会话标识符进行访问。

锁机制

具体来说,文件锁通常分为两种类型:

  1. 共享锁(Shared Lock):多个进程或线程可以同时获取文件的共享锁,以进行读操作。共享锁不会阻塞其他进程或线程的读操作,但会阻塞写操作。
  2. 独占锁(Exclusive Lock):只有一个进程或线程可以获取文件的独占锁,以进行写操作。独占锁会阻塞其他进程或线程的读和写操作。

http和http协议

安全性:HTTP:HTTP是不安全的协议,所有数据以明文形式传输,容易被中间人攻击拦截和窃取敏感信息。HTTPS:HTTPS通过在HTTP协议上添加安全性特性,使用SSL/TLS协议对数据进行加密和认证。这意味着在HTTPS通信中,数据在传输过程中经过加密,不容易被窃取或篡改,从而提供了更高的安全性。

加密:HTTP:HTTP不提供数据加密功能,因此所有数据都是明文传输的。HTTPS:HTTPS使用SSL/TLS协议来加密通信数据,确保数据在传输过程中保持机密性。

认证:HTTP:HTTP不提供服务器身份验证机制,因此难以确保连接的终端是否与预期的服务器相连。HTTPS:HTTPS使用数字证书来验证服务器的身份,确保连接到的是正确的服务器。这可以防止中间人攻击。

为什么要划分进程与线程

  1. 资源隔离:进程:每个进程都有自己独立的内存空间,因此进程之间的数据互相隔离。这意味着一个进程的错误或崩溃通常不会影响其他进程。线程:线程共享同一进程的内存空间,因此它们可以更轻松地共享数据和通信。但也因此,一个线程的错误可能会影响同一进程内的其他线程。
  2. 创建和销毁开销:进程:创建和销毁进程通常比较耗时,因为每个进程都需要分配独立的内存空间和系统资源。线程:创建和销毁线程的开销相对较小,因为它们共享相同的进程资源。
  3. 并发性:进程:进程之间的并发性较低,因为进程的切换涉及到上下文切换和资源重分配。线程:线程之间的并发性较高,因为它们可以更轻松地共享数据和通信,而不需要切换进程。
  4. 多核利用:进程:多核处理器可以并行执行多个进程,从而提高系统的性能。线程:多核处理器可以并行执行多个线程,从而更有效地利用多核资源。
  5. 任务分配:进程:通常用于执行独立的任务,不需要频繁地共享数据。线程:通常用于执行与主任务相关的子任务,需要频繁地共享数据。

你可能感兴趣的:(面试题记录,开发语言,面试,美团)