招银网络一面总结

比较简单的面试题,大部分都是常见的八股,大部分我也回答上来了,最后反问环节的时候问对我的面试满意不满意,他也说技术还行,不过表达有问题。自我感觉要是不是把我当KPI的话,大概还是会有二面的吧。不过确实自己还是稍微有点紧张了,讲起来不是那么连贯,不过招行这个面试也算是自己的第一场面试了,给后面的面试积累一点经验吧。

面试问题

自我介绍


问项目有没有用到实际生产之中

老实回答,项目是练手项目


问简历上的实习经历,微信推送这样的公共接口怎样保证安全性的

微信服务器后台配置token,接口接收到参数并用配置的token进行AES加密,并与接口发送来的签名对比,验证该请求由微信服务器发送来的。

追问:AES是什么加密?

AES是对称加密,由于加密口令只保存在本地和微信服务器上,所以对称加密也是能保证安全性的。


微服务项目和单体项目有什么区别

Q:微服务存在彼此之间的调用。

微服务项目和单体项目是两种不同的软件架构模式,它们在项目结构、部署方式、开发模式等方面存在显著的区别。

  1. 项目结构

    • 单体项目:单体项目通常由一个单独的应用程序组成,所有的功能和模块都在同一个代码库中。这种项目结构通常采用单一的部署单元,所有的功能都打包在一起。
    • 微服务项目:微服务项目将一个大型应用拆分为多个小型服务,每个服务都有自己独立的代码库和数据存储。每个服务通常负责一个特定的业务功能或模块。
  2. 部署方式

    • 单体项目:单体项目通常以单一的部署单元进行部署,整个应用程序作为一个整体运行在一个服务器或容器中。
    • 微服务项目:微服务项目中的每个服务都可以独立部署,每个服务可以运行在不同的服务器、容器或云上的容器编排平台中。
  3. 开发模式

    • 单体项目:在单体项目中,所有的功能都集中在一个代码库中,开发和测试相对简单,但项目规模较大时,代码维护和升级可能变得复杂。
    • 微服务项目:微服务项目中,每个服务都是独立开发、测试和部署的,这允许团队更专注于特定功能或模块的开发,但也需要更多的协调和集成工作。
  4. 扩展性

    • 单体项目:单体项目的扩展性有限,通常需要水平扩展整个应用程序,这可能需要更多的资源。
    • 微服务项目:微服务项目可以根据需要独立扩展每个服务,这样可以更灵活地分配资源,提高性能。
  5. 维护和升级

    • 单体项目:单体项目的维护和升级通常需要停止整个应用程序,进行全局性的升级,这可能导致系统的不可用时间较长。
    • 微服务项目:微服务项目中的每个服务可以独立维护和升级,降低了系统不可用时间。
  6. 复杂性

    • 单体项目:单体项目的复杂性较低,适合小型应用或初期阶段的项目。
    • 微服务项目:微服务项目的复杂性较高,适合大型和复杂的应用,能够更好地应对业务需求的变化。

总的来说,微服务项目适合需要高度可扩展性、灵活性和独立部署的场景,但也带来了更多的复杂性和管理挑战。单体项目适合较小规模的应用,开发和维护相对简单。选择适合的架构模式应根据项目的需求和规模来决定。


追问:微服务调用为什么要用Kafka?

Q:解耦,削峰,异步


怎么理解Java是纯面向对象的语言?

Q:Java写的就是一个个Class文件,实现的也是各个方法。

Java被称为一种纯面向对象的编程语言,这是因为它在设计和实现上遵循了面向对象编程(Object-Oriented Programming,OOP)的核心原则,并且在语言层面提供了对面向对象编程概念的直接支持。下面是解释Java是纯面向对象语言的关键特征和原则:

  1. 一切都是对象:在Java中,一切都被视为对象。无论是基本数据类型(如整数、字符、布尔值)还是用户自定义的类,都被视为对象。

  2. 类和对象:Java通过类(Class)来定义对象的属性和行为。类是对象的模板,而对象是根据类创建的实例。这种类与对象的关系是OOP的核心。

  3. 封装:Java支持封装,即将数据和方法封装在类中,通过访问控制修饰符(public、private、protected)控制对类的成员的访问权限,从而隐藏了内部实现的细节。

  4. 继承:Java允许创建子类(派生类)来继承父类(基类)的属性和方法。这支持了代码重用和构建层次结构。

  5. 多态:Java支持多态,允许不同的对象对相同的方法做出不同的响应。这提高了代码的灵活性和可扩展性。

  6. 抽象类和接口:Java允许定义抽象类和接口,这些抽象概念支持更高级别的抽象和多态性。

  7. 动态绑定:Java中的方法调用通常是动态绑定的,这意味着方法的调用是在运行时解析的,而不是在编译时。

  8. 垃圾回收:Java提供了垃圾回收机制,自动管理对象的生命周期,程序员不需要手动释放内存。

  9. 异常处理:Java使用异常机制来处理错误和异常情况,这支持了更健壮的代码。

  10. 一致性:Java的语法和设计模式都强调一致性和规范性,使得代码易于理解和维护。

总的来说,Java的设计和语法在多个层面上都遵循了面向对象编程的原则,提供了丰富的工具和机制来创建、组织和管理对象,使得Java被广泛用于开发大规模、复杂的应用程序,并支持了面向对象编程的核心理念。这些特征使得Java成为一种纯粹的面向对象的编程语言。


追问:面向对象和面向过程的优缺点

Q:举例:把大象装进冰箱

面向对象编程(Object-Oriented Programming,OOP)和面向过程编程(Procedural Programming,PP)是两种不同的编程范式,它们各自具有一些优点和缺点,适用于不同的编程需求。

面向对象编程(OOP)的优点:

  1. 模块化和复用性:OOP通过类和对象的概念,将代码模块化,使得代码更易于理解和维护。同时,类的复用性更高,可以在不同的项目中重复使用。

  2. 封装:OOP支持封装,将数据和行为封装在对象中,隐藏了内部实现的细节,提高了代码的安全性和可维护性。

  3. 继承:OOP允许通过继承机制创建新的类,这种层次结构有助于代码重用和扩展。

  4. 多态:多态性允许不同对象对相同的方法做出不同的响应,提高了代码的灵活性和可扩展性。

  5. 代码的可读性:OOP的代码通常更易于阅读和理解,因为它反映了现实世界中的对象和关系。

面向对象编程(OOP)的缺点:

  1. 学习曲线:OOP的概念相对复杂,对于初学者来说,学习曲线可能较陡峭。

  2. 性能开销:相对于面向过程编程,OOP可能会引入一定的性能开销,因为对象之间的交互需要额外的处理。

面向过程编程(PP)的优点:

  1. 简单性:面向过程编程通常更简单直接,适合小型项目和简单任务。

  2. 性能:在某些情况下,面向过程编程可能更高效,因为它没有对象之间的开销。

面向过程编程(PP)的缺点:

  1. 可维护性:随着项目的复杂性增加,面向过程编程往往导致难以维护的代码。代码不够模块化,难以理解。

  2. 复用性:面向过程编程通常不支持高级别的代码复用,需要重复编写相似的代码。

  3. 可读性:随着项目复杂度的增加,面向过程编程的代码可能会变得难以阅读和理解。

综上所述,选择面向对象编程还是面向过程编程取决于项目的规模、复杂度和需求。通常,大型和复杂的项目更适合使用面向对象编程,因为它提供了更好的代码组织和维护能力。而小型和简单的任务可能更适合使用面向过程编程,因为它更简单和高效。此外,现代编程语言通常提供了两种编程范式的混合使用,以满足不同的需求。


Java存在内存泄漏吗?

听成内存溢出了,讲了一半忽然意识到是问内存泄漏,于是举例Threadlocal的内存泄漏问题。

是的,Java程序中也存在内存泄漏的情况。尽管Java具有自动内存管理机制(垃圾回收),但仍然有一些情况会导致内存泄漏。以下是一些可能导致Java内存泄漏的常见情况:

  1. 未关闭资源:如果在使用文件、数据库连接、网络套接字等资源时未显式关闭它们,这些资源可能会泄漏,导致内存占用不断增加。

  2. 循环引用:如果对象之间存在循环引用,即使这些对象不再被程序使用,垃圾回收器也无法回收它们,因为它们之间的引用仍然存在。

  3. 静态集合:在静态集合(如静态列表、静态映射)中存储对象,这些对象将一直存在于整个应用程序的生命周期中,除非手动从集合中移除。

  4. 内部类:内部类持有对外部类的引用,如果内部类的实例被长时间持有,外部类也会一直存在,无法被垃圾回收。

  5. 不合理的线程管理:线程内存泄漏是一个常见问题。如果线程未正确关闭或终止,它们可能会持有对其他对象的引用,导致内存泄漏。

  6. 弱引用和软引用未正确使用:Java提供了弱引用和软引用来管理对象的生命周期,如果未正确使用这些引用类型,可能会导致对象过早或过晚地被回收。

为了避免内存泄漏,Java开发者应该仔细管理资源、避免循环引用、及时关闭不再需要的对象、正确使用引用类型等。同时,可以使用内存分析工具(如Eclipse Memory Analyzer)来检测和解决潜在的内存泄漏问题。尽管Java有垃圾回收机制,但仍需要开发者的注意和维护来确保应用程序的内存使用健康。


Java如何处理异常的?

Q:讲了受检查异常和非受检查异常,感觉还能讲讲异常上抛的问题,当时忘记了。

在Java中,异常处理是通过使用异常处理机制来处理和捕获异常情况的。以下是Java中处理异常的主要方法:

  1. 使用try-catch块:可以使用try-catch块来捕获和处理异常。在try块中编写可能引发异常的代码,然后在catch块中捕获并处理异常。例如:
1
2
3
4
5
6
7
8
9
try {
// 可能引发异常的代码
} catch (ExceptionType1 e1) {
// 处理ExceptionType1类型的异常
} catch (ExceptionType2 e2) {
// 处理ExceptionType2类型的异常
} finally {
// 可选的finally块,用于清理资源
}
  1. 使用throws关键字:如果不想在方法内捕获异常,可以使用throws关键字在方法签名中声明方法可能抛出的异常。这将把异常传递给调用该方法的代码,由调用者来处理异常。
1
2
3
public void myMethod() throws MyException {
// 可能抛出MyException异常的代码
}
  1. 自定义异常类:可以创建自定义异常类,继承自Java内置的异常类(如Exception或RuntimeException),以便更好地表示特定类型的异常情况。
1
2
3
4
5
6
public class MyException extends Exception {
// 自定义异常类的构造函数
public MyException(String message) {
super(message);
}
}
  1. 使用finally块:finally块是可选的,用于确保在发生异常或不发生异常的情况下都能执行的代码块。通常用于资源的清理工作,如关闭文件或数据库连接。
1
2
3
4
5
6
7
try {
// 可能引发异常的代码
} catch (Exception e) {
// 处理异常
} finally {
// 清理资源的代码
}
  1. 使用try-with-resources:在Java 7及更高版本中引入了try-with-resources语句,用于自动关闭实现了AutoCloseable接口的资源,如文件流或数据库连接。这有助于减少资源泄漏的风险。
1
2
3
4
5
try (ResourceType resource = new ResourceType()) {
// 使用资源的代码
} catch (Exception e) {
// 处理异常
}
  1. 抛出异常:使用throw关键字可以在代码中手动抛出异常。通常用于自定义异常情况。
1
2
3
if (someCondition) {
throw new MyException("This is a custom exception.");
}

Java异常处理机制允许程序员捕获和处理异常,以提高程序的稳定性和可靠性。通过适当处理异常,可以避免程序崩溃,并提供有用的错误信息,以便进行故障排除和日志记录。


Spring的Controller,Service出现异常怎么处理?

Q:讲了用AOP异常处理器来处理

在Spring应用中,可以使用不同的方式来处理Controller和Service层出现的异常,以确保应用的稳定性和可维护性。以下是处理异常的一些常见方法:

  1. 使用try-catch块:在Controller或Service的方法中使用try-catch块来捕获异常,并进行适当的处理。这可以防止异常传播到更高级别的代码,并允许您执行特定的异常处理逻辑。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Controller
public class MyController {

@Autowired
private MyService myService;

@RequestMapping("/myEndpoint")
public String handleRequest() {
try {
// 调用Service方法,可能会抛出异常
myService.doSomething();
return "success";
} catch (CustomException e) {
// 处理自定义异常
return "error";
} catch (Exception e) {
// 处理其他异常
return "generic_error";
}
}
}
  1. 使用@ControllerAdvice和@ExceptionHandler:Spring提供了@ControllerAdvice注解和@ExceptionHandler注解,用于全局处理Controller层的异常。您可以创建一个全局异常处理类,将异常处理方法与@ControllerAdvice注解一起使用,并在方法中指定要处理的异常类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(CustomException.class)
public String handleCustomException() {
// 处理自定义异常
return "error";
}

@ExceptionHandler(Exception.class)
public String handleGenericException() {
// 处理其他异常
return "generic_error";
}
}
  1. 使用Spring AOP:使用Spring的切面编程(AOP),可以定义切面来捕获和处理Service层方法的异常。通过定义切面,可以将异常处理逻辑从业务逻辑中分离出来,提高代码的模块性。

  2. 使用自定义异常:在Service层中,可以定义自定义异常类,用于表示特定的业务异常情况。当业务发生异常时,抛出自定义异常,并在Controller层捕获和处理这些异常,以提供有意义的错误信息给客户端。

  3. 使用全局异常处理器:除了@ControllerAdvice,您还可以使用Spring Boot的全局异常处理器来处理整个应用程序的异常。在Spring Boot中,可以创建一个实现ErrorController接口的类,来处理未捕获的全局异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
public class MyErrorController implements ErrorController {

@Override
public String getErrorPath() {
return "/error";
}

@RequestMapping("/error")
public String handleError() {
// 处理全局异常
return "global_error";
}
}

无论您选择哪种方法,都应该根据具体的应用需求和项目结构来决定如何处理异常。重要的是确保异常处理逻辑能够提供有用的错误信息,并确保应用的稳定性。


数据库三范式

Q:中午才看了,结果理解不了,说的不是很清楚,寄。

数据库三范式(Normalization)是关系数据库设计中的一种重要规范化过程,旨在消除数据冗余、提高数据存储效率、降低数据更新异常的发生。三范式分为以下三个层次:

  1. 第一范式(1NF)

    • 每个数据表中的每一列都必须包含原子值,即每一列不能再分解成更小的数据项。
    • 保证表中的数据不包含重复的分组。
  2. 第二范式(2NF)

    • 必须满足第一范式(1NF)。
    • 所有非主键列必须完全依赖于主键,即非主键列不能部分依赖于主键。
    • 通常需要将非主键列拆分到另一个表中,并通过主键关联。
  3. 第三范式(3NF)

    • 必须满足第二范式(2NF)。
    • 非主键列之间不能存在传递依赖关系,即非主键列不能间接依赖于主键。
    • 需要将传递依赖关系中的非主键列拆分到其他表中,并通过外键关联。

通过遵循三范式,可以有效减少数据冗余、提高数据库的性能和可维护性。然而,有时候为了满足特定的查询需求,可能需要违反某些范式,从而在设计中进行权衡。

此外,还有更高级别的范式,如BCNF(Boyce-Codd Normal Form)和4NF(Fourth Normal Form),用于处理更复杂的数据结构和依赖关系。选择适当的范式取决于特定应用的需求和性能考虑。


自己练习的项目设计的表有几张表

有二十多张表

追问:是否使用过外键?

Q:没太懂意思,以为是用外键约束,直接就说没用过,直接联表查询的。

在MySQL中,您可以使用外键约束(Foreign Key Constraint)来确保数据完整性,特别是在多个表之间建立关联关系。外键约束可以确保在一个表的列(子表)中的值存在于另一个表的列(父表)中。

以下是如何在MySQL中使用外键约束的基本步骤:

  1. 创建父表:首先,创建包含您希望引用的数据的表,通常称为父表。这个表中的列将被其他表引用。

    1
    2
    3
    4
    CREATE TABLE Parent (
    parent_id INT PRIMARY KEY,
    parent_name VARCHAR(255)
    );
  2. 创建子表:接下来,创建包含外键列的表,通常称为子表。外键列将引用父表中的列。

    1
    2
    3
    4
    5
    6
    CREATE TABLE Child (
    child_id INT PRIMARY KEY,
    child_name VARCHAR(255),
    parent_id INT,
    FOREIGN KEY (parent_id) REFERENCES Parent(parent_id)
    );

    在上面的例子中,Child表中的parent_id列被定义为外键,它引用了Parent表中的parent_id列。

  3. 建立外键关系:通过使用FOREIGN KEY关键字和REFERENCES子句,将子表的外键列与父表的主键列建立关联。这将确保子表中的外键值必须存在于父表中的主键列中。

  4. 处理外键约束违规:如果尝试在子表中插入或更新行时违反了外键约束,MySQL将拒绝操作,并抛出一个错误。您可以选择处理这些错误,例如通过回滚事务或执行其他适当的操作。

  5. 删除外键约束:如果需要,您可以通过使用ALTER TABLE语句删除外键约束。例如:

    1
    ALTER TABLE Child DROP FOREIGN KEY child_ibfk_1;

    上述命令将删除名为child_ibfk_1的外键约束。

使用外键约束有助于确保数据库中的数据完整性,特别是在涉及多个表的复杂关系时。这可以防止不一致的数据插入或更新,提高数据质量和可维护性。

补充:为什么不建议使用外键约束?

虽然外键约束可以在数据库中确保数据的一致性和完整性,但在某些情况下,不建议使用外键约束可能会更有利于性能和灵活性。以下是一些不建议使用外键约束的情况:

  1. 性能考虑:外键约束会增加数据库的维护开销,包括索引维护和数据验证。在高并发的环境中,这些额外的开销可能会导致性能下降。如果对性能有严格要求,可以考虑在应用层面进行数据验证和处理,而不是依赖数据库的外键约束。

  2. 复杂性:外键约束引入了数据库结构的复杂性,可能需要更多的管理和维护。在某些情况下,特别是对于小型项目或简单数据模型,这种复杂性可能是不必要的。

  3. 跨数据库兼容性:如果您的应用需要跨多个数据库管理系统(如MySQL、PostgreSQL、Oracle等)部署,外键约束可能不太适合,因为不同的数据库系统对外键的支持和实现方式可能会有所不同。

  4. 数据迁移和备份:外键约束可能会在数据迁移和备份时引发问题。在将数据从一个环境迁移到另一个环境时,外键约束可能需要额外的处理,以确保数据的一致性。

  5. 应用逻辑:某些应用程序可能有复杂的逻辑要求,而外键约束可能无法满足这些需求。在这种情况下,应用程序层面的数据验证和处理可能更灵活。

总的来说,是否使用外键约束取决于项目的具体需求和性能要求。对于某些项目,外键约束是必不可少的,可以确保数据的完整性。但在其他情况下,根据项目的规模、性能需求和复杂性,可能会选择不使用外键约束,而依赖应用层面的验证和处理来确保数据的一致性。


MySQL有几种联表查询方式?有何区别?

Q:三种,内连接,左连接,右连接。

在MySQL中,常见的联表查询方式包括以下几种,它们的区别主要体现在语法和适用场景上:

  1. INNER JOIN(内连接)

    • INNER JOIN 是最常用的联表查询方式之一,它返回两个表中匹配行的交集。
    • 语法示例:
      1
      SELECT * FROM table1 INNER JOIN table2 ON table1.column_name = table2.column_name;
  2. LEFT JOIN(左连接)

    • LEFT JOIN 返回左表中的所有行和右表中与左表匹配的行。
    • 如果右表中没有匹配的行,将会返回 NULL 值。
    • 语法示例:
      1
      SELECT * FROM table1 LEFT JOIN table2 ON table1.column_name = table2.column_name;
  3. RIGHT JOIN(右连接)

    • RIGHT JOIN 类似于 LEFT JOIN,但返回右表中的所有行和左表中与右表匹配的行。
    • 如果左表中没有匹配的行,将会返回 NULL 值。
    • 语法示例:
      1
      SELECT * FROM table1 RIGHT JOIN table2 ON table1.column_name = table2.column_name;
  4. FULL JOIN(全连接)

    • FULL JOIN 返回左表和右表中的所有行,如果没有匹配的行,将会返回 NULL 值。
    • FULL JOIN 在某些数据库中可能不被支持,MySQL 通常使用 UNION ALL 来模拟 FULL JOIN。
    • 语法示例:
      1
      SELECT * FROM table1 FULL JOIN table2 ON table1.column_name = table2.column_name;
  5. CROSS JOIN(交叉连接)

    • CROSS JOIN 返回两个表中的所有可能组合,它不基于任何条件匹配。
    • 通常用于创建笛卡尔积。
    • 语法示例:
      1
      SELECT * FROM table1 CROSS JOIN table2;

这些联表查询方式可以根据具体的业务需求来选择,以获取所需的数据。INNER JOIN、LEFT JOIN 和 RIGHT JOIN 是最常用的联表查询方式,它们可以帮助您从多个表中检索和组合数据。

补充:讲讲笛卡尔积问题

在数据库中,笛卡尔积(Cartesian Product)是指将两个或多个表的行组合在一起,生成一个新表的操作。这个新表包含了来自每个表的每一行的所有可能的组合。笛卡尔积是一种非常耗费计算资源的操作,特别是当参与笛卡尔积的表非常大时,容易导致性能问题。

下面让我更详细地解释笛卡尔积问题以及如何避免它:

1. 笛卡尔积问题: 笛卡尔积通常是一个意外的错误,当没有明确指定连接条件(如JOIN)时,或者连接条件不正确时,可能会发生。这导致了不必要的数据膨胀,结果集包含了大量无用的行,使查询变得非常低效,同时消耗了大量的计算和存储资源。

2. 如何避免笛卡尔积问题:

  • 明确指定连接条件: 在进行表连接操作时,一定要明确指定连接条件,以确保只有符合条件的行被组合在一起。例如,使用 INNER JOIN、LEFT JOIN、RIGHT JOIN 等连接类型,并在 ON 子句中指定连接条件。

  • 使用合适的索引: 确保表中的连接条件字段上存在适当的索引。索引可以显著提高连接操作的性能,特别是在大型表上。

  • 小心多表连接: 当连接多个表时要格外小心,因为每个额外的表参与连接会增加笛卡尔积的可能性。如果不需要连接的表数据,可以考虑将其子查询或者使用其他方法分离出来,而不是直接连接。

  • 使用合适的工具和框架: 一些数据库工具和ORM(对象关系映射)框架可以自动帮助您生成正确的连接条件,减少笛卡尔积的风险。

3. 示例:

假设有两个表 CustomersOrders,我们想要查询每个客户的订单。如果我们使用了错误的连接条件或没有连接条件,可能会导致笛卡尔积问题:

1
2
-- 错误的查询,可能导致笛卡尔积
SELECT * FROM Customers, Orders;

为了避免笛卡尔积,正确的查询应该如下所示,明确指定连接条件:

1
2
3
-- 正确的查询,指定了连接条件
SELECT * FROM Customers
INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID;

总之,理解笛卡尔积问题以及如何避免它对于数据库查询和性能优化非常重要。确保在查询中始终明确指定连接条件,并小心处理多表连接的情况,以减少性能问题的发生。


用过MySQL的执行计划吗?

Q:用过,进行SQL调优的时候,用explain关键字分析SQL

追问:用explain分析SQL的时候关注哪些东西?

Q:忘记了能看到哪些结果了,只说了走不走索引,建议索引

使用 EXPLAIN 命令分析 SQL 查询时,需要关注以下关键信息,以评估查询的性能和优化可能性:

  1. id: 这是查询的唯一标识符,通常从 1 开始递增。在查询中有多个 SELECT 语句时,可以用来标识执行的顺序。

  2. select_type: 这表示查询的类型,可以是以下之一:

    • SIMPLE:简单查询,不包含子查询或 UNION。
    • PRIMARY:最外层查询。
    • SUBQUERY:子查询。
    • DERIVED:派生表查询,通常在 FROM 子句中使用。
    • UNION:UNION 查询。
    • 等等。
  3. table: 这是查询涉及的表的名称。

  4. type: 这表示连接类型,用于描述如何访问表,常见的值包括:

    • ALL:全表扫描,没有索引。
    • index:使用了索引。
    • range:使用索引来进行范围扫描。
    • ref:使用非唯一索引来匹配某个值。
    • eq_ref:使用唯一索引来匹配某个值。
    • const:通过索引直接访问单个行。
    • system:只有一行(例如 SELECT COUNT(*))。
  5. possible_keys: 这列出了可能用于查询的索引名称。MySQL 查询优化器会考虑哪个索引可能最优。

  6. key: 这是查询实际使用的索引名称。如果为 NULL,则表示没有使用索引。

  7. key_len: 表示索引的长度。较短的索引通常更有效。

  8. ref: 这列出了用于索引查找的列或常量。

  9. rows: 表示查询返回的行数估计值。

  10. filtered: 这表示查询结果中的行数百分比,表示过滤条件的效果。

  11. Extra: 这包含了关于查询执行的其他信息,例如是否使用了文件排序、临时表等。

通过分析 EXPLAIN 的输出,可以确定查询是否有效使用了索引,是否需要优化查询或添加新的索引,以及哪些部分可能需要进一步的性能调整。在数据库优化中,理解和利用 EXPLAIN 是一个关键的工具。


讲讲http里的cookie和session

Q:这个还是比较懂得,感觉自己讲的比较清楚,从http的无状态引出了sessionId,以及session和cookie的作用和区别。

HTTP(Hypertext Transfer Protocol)是一种用于在Web上传输数据的协议。在Web应用中,Cookie 和 Session 是两种用于跟踪用户状态和信息的机制,它们在HTTP协议中起到了重要的作用。

Cookie:

  1. 定义: Cookie 是一小段文本信息,由服务器发送给用户的浏览器,并存储在用户的本地计算机上。浏览器在后续请求中会自动将 Cookie 发送回服务器,以便服务器识别用户。

  2. 用途: Cookie 主要用于跟踪用户的状态和存储一些客户端的信息,如登录凭证、购物车内容、语言偏好等。

  3. 工作原理: 当服务器向客户端发送响应时,可以通过响应头中的 Set-Cookie 字段设置一个或多个 Cookie。浏览器会将这些 Cookie 存储在本地。在后续请求中,浏览器会自动在请求头中添加 Cookie 字段,将之前存储的 Cookie 信息发送给服务器。服务器可以通过解析请求头中的 Cookie 字段来获取客户端的状态信息。

  4. 特点:

    • Cookie 存储在客户端,有大小限制。
    • 可以设置过期时间和域名,使得 Cookie 可以在一定时间内保持有效。
    • 可以通过 JavaScript 在客户端进行操作,但受同源策略限制。
    • 不适合存储敏感信息,因为 Cookie 的内容可以被客户端查看和修改。

Session:

  1. 定义: Session 是一种服务器端的机制,用于跟踪用户的状态。每个用户会话都有一个唯一的标识符(Session ID),用于关联用户和服务器端的数据。

  2. 用途: Session 主要用于存储用户的登录状态、购物车、用户设置等信息。

  3. 工作原理: 当用户第一次访问网站时,服务器会创建一个唯一的 Session ID,并将其存储在 Cookie 中,然后将 Session 数据存储在服务器上。后续请求中,浏览器会将 Session ID 自动发送给服务器,服务器通过 Session ID 来获取对应用户的 Session 数据。

  4. 特点:

    • Session 数据存储在服务器端,安全性较高。
    • 服务器端的存储可以是内存、数据库等,具体取决于应用程序的配置。
    • 可以存储大量数据,不受浏览器 Cookie 大小限制。
    • 可以存储敏感信息,因为 Session 数据在客户端不可见。

区别:

  • 存储位置:Cookie 存储在客户端,Session 存储在服务器端。
  • 数据容量:Cookie 有大小限制,Session 可以存储大量数据。
  • 安全性:Session 更安全,因为数据存储在服务器端。
  • 敏感信息:不建议在 Cookie 中存储敏感信息,但可以在 Session 中存储。

在实际应用中,通常会同时使用 Cookie 和 Session。Cookie 用于存储 Session ID,而 Session 用于存储用户的状态和信息。这两者结合起来实现了用户跟踪和状态管理的功能。

追问:浏览器禁用cookie之后,session还能不能使用?

Q:这个真没想过,不过自己分析禁用了cookie之后,也拿不到sessionId了,应该session也用不了了,于是就会回答不能,此时浏览器进入无痕模式。

当浏览器禁用了Cookie时,会影响到使用传统的基于Cookie的Session管理机制。因为Session的实现通常依赖于Cookie来存储Session ID,以标识和跟踪用户会话。

如果浏览器禁用了Cookie,那么Session仍然可以使用,但需要考虑替代方案:

  1. URL 重写(URL Rewriting): 这是一种常见的替代Cookie的方式。在每个URL中添加Session ID参数,服务器在接收到请求时从URL中解析出Session ID,然后使用它来查找和管理用户会话。这种方式不依赖于Cookie,但会让URL变得更长,并且需要在服务器端进行额外的处理。

  2. 隐藏表单字段(Hidden Form Fields): 在HTML表单中添加一个隐藏的字段,用于存储Session ID。用户提交表单时,Session ID会随着表单数据一起发送到服务器。服务器端通过解析表单字段来获取Session ID。

  3. HTTP 头信息: 可以通过自定义HTTP头信息来传递Session ID,然后在服务器端进行解析和处理。

  4. LocalStorage 或其他存储机制: 在一些现代Web应用中,可以使用Web存储(如LocalStorage)来存储Session信息,而不依赖于Cookie。这需要在前端和后端进行额外的开发工作。

需要注意的是,禁用Cookie会对用户体验和开发工作产生一些不便,因为传统的基于Cookie的Session管理机制是最常用和便捷的方式。在禁用Cookie的情况下,需要更多的前后端开发工作来实现替代方案,同时需要保持安全性和用户隐私。


反问环节

公司的业务是怎么样的

刚才那个禁用cookie的问题我回答正确了吗?

对我的面试有什么建议


追加提问

本来要结束了的,面试官忽然又问了一句你不是科班生技术哪里学的?

直接就说电子信息也是计算机大类,和计算机科学学的课程其实大差不差,不过最主要的还是课后自己看书看视频,跟着实验室老师做实际项目。