一、java基础
1.Java集合类框架的基本接口有哪些?分别说说他们的特点?
- Collection(集合接口):代表一组对象的集合,提供了对集合进行基本操作的方法,如添加、删除、遍历等。特点包括:
-
- 不允许存储重复的元素。
- 允许存储多个null元素。
- List(列表接口):继承自Collection接口,表示有序、可重复的元素序列。特点包括:
-
- 可以存储重复的元素。
- 提供了按索引访问元素的方法,如get和set。
- 实现类有ArrayList、LinkedList和Vector等。
- Set(集接口):继承自Collection接口,表示无序、不重复的元素集合。特点包括:
-
- 不允许存储重复的元素。
- 通常实现类根据元素的哈希值来确定元素是否相同。
- 实现类有HashSet、TreeSet等。
- Map(映射接口):表示键值对(key-value)的映射,每个键最多只能映射到一个值。特点包括:
-
- 键是唯一的,值可以重复。
- 提供了根据键获取值的方法,如get和put。
- 实现类有HashMap、TreeMap和LinkedHashMap等。
这些接口组成了Java集合类框架的基础,通过不同的实现类可以满足不同的需求,提供了丰富的数据结构和操作方法,方便开发人员进行集合相关的操作和算法设计。
2.Java中Exception和Error有什么区别?
- 继承关系:Exception和Error都是Throwable类的子类。Exception是应用程序可以处理的异常类,而Error表示系统错误或资源耗尽等严重问题,通常无法逆转或恢复。
- 引起原因:Exception通常由应用程序代码引起,表示在正常的应用程序运行过程中可能出现的可捕获异常,如输入错误、网络连接问题等。而Error通常由JVM或底层系统引起,表示严重的故障或资源不足,如内存溢出、虚拟机崩溃等。
- 是否可捕获:Exception属于可检查异常(checked exception),在代码中必须显式处理或声明抛出。而Error属于不可检查异常(unchecked exception),一般不需要应用程序显式处理。
- 可恢复性:Exception通常表示可以通过异常处理机制进行恢复。应用程序可以通过捕获和处理异常来处理问题,继续执行或采取其他合适的措施。而Error一般表示无法恢复的问题,应用程序很少能够处理或修复这些错误,通常会导致程序终止或崩溃。
总结来说,Exception代表可预见的可处理异常,通常需要应用程序进行处理;而Error代表严重故障或不可恢复的问题,通常无法由应用程序处理,它们一般由JVM或底层系统报告并处理。
3、面向对象的三大特性?
面向对象编程(Object-oriented Programming,简称OOP)的三大特性是封装、继承和多态。
- 封装(Encapsulation):封装是将数据和对数据的操作封装在一个单元中,以形成一个对象。通过封装,对象对外部隐藏了内部的实现细节,只暴露必要的接口供其他对象使用。这样可以提高系统的安全性、可靠性和可维护性,同时也方便了代码的复用。
- 继承(Inheritance):继承允许新创建的类(子类)基于现有类(父类或超类)来继承其属性和方法。子类可以继承父类的特征,并且可以在此基础上添加自己特有的属性和方法。继承提供了类之间的层次关系,使得代码可以更加模块化、易于扩展和维护。
- 多态(Polymorphism):多态是指同一种操作可以在不同的对象上具有不同的行为。多态使得可以通过统一的方式调用不同类的对象所具有的共同方法,而无需关心具体对象的类型。通过多态,可以增加代码的灵活性和可扩展性,使程序能够适应不同的场景和需求。
这些特性使得面向对象编程成为一种强大而灵活的编程范式,可以更好地组织和管理复杂的代码逻辑,提高代码的可读性、可维护性和可扩展性。
4、Java8种基本数据类型?
- byte:字节型,占用1个字节,范围为-128到127。
- short:短整型,占用2个字节,范围为-32,768到32,767。
- int:整型,占用4个字节,范围为-2,147,483,648到2,147,483,647。
- long:长整型,占用8个字节,范围为-9,223,372,036,854,775,808到9,223,372,036,854,775,807。
- float:单精度浮点型,占用4个字节,范围为约±3.40282347E+38F(有效位数为6-7位)。
- double:双精度浮点型,占用8个字节,范围为约±1.79769313486231570E+308(有效位数为15位)。
- char:字符型,占用2个字节,表示一个Unicode字符。
- boolean:布尔型,占用1个字节,值为true或false。
这些基本数据类型提供了不同的数据存储范围和精度,可以满足不同场景下的数据处理需求。在使用时,可以根据需求选择合适的数据类型来存储和操作数据。
5、java新特性
- Java 8 新特性:
-
- Lambda 表达式:Lambda 表达式允许以更简洁的方式编写匿名函数,使代码更易读和编写。
- Stream API:Stream API 提供了一种便捷的处理集合数据的方式,支持函数式编程风格的操作,如过滤、映射、归约等。
- 函数式接口和默认方法:引入了函数式接口(Functional Interface)概念,并允许接口中定义默认方法和静态方法。
- 新的日期/时间 API:引入了java.time 包,提供了全新的日期和时间处理 API。
- Java 9 新特性:
-
- 模块化系统:引入了模块化开发概念,通过模块(Module)进行代码组织和依赖管理,提升可维护性和安全性。
- JShell:引入了交互式命令行工具 JShell,可以在命令行实时执行和测试代码片段。
- 私有接口方法:接口中可以定义私有方法,提供了在接口内部共享代码的机制。
- 改进的编译器性能:引入了一系列编译器改进,如增量编译和改进的 JIT 编译器等。
- Java 10 新特性:
-
- 局部变量类型推断:引入了局部变量类型推断,允许使用 var 关键字声明变量,由编译器自动推断变量类型。
- 应用类数据共享(Application Class-Data Sharing):通过 CDS 机制,可以在多个 JVM 实例之间共享类元数据,提高启动和内存占用效率。
- Java 11 新特性:
-
- HTTP 客户端 API:引入了原生的 HTTP 客户端 API,简化了进行 HTTP 请求和响应处理的操作。
- 支持动态类文件(Dynamic Class File):允许直接以字符串形式生成和加载类文件,降低了动态代码生成的复杂度。
- Java 12、13、14、15、16 的新特性:
-
- 这些版本引入了一系列改进和增强,包括新的语言特性、JVM 改进、API 增加等,如Switch 表达式、文本块、ZGC(低延迟垃圾回收器)等。
请注意,以上仅列举了一些较为重要的新特性,Java 在每个版本中都会有一些改进和新功能的引入。最新的 Java 版本可参考官方文档或相关资料了解更多详情。
6、List 集合中 add0和addAll0 有什么区别?
在 Java 的 List 集合中,add(0) 和 addAll(0) 方法都用于将元素插入到指定的位置。它们的区别如下:
- add(0) 方法:
-
- add(0, element) 方法用于将指定的元素添加到列表的开头(索引为0的位置)。
- 如果列表中已经存在元素,则将现有的元素右移一个位置,以便为新元素腾出空间。
- 插入后,列表的长度会增加1。
- addAll(0) 方法:
-
- addAll(0, collection) 方法用于将指定集合中的所有元素插入到列表的开头(索引为0的位置)。
- 类似于 add(0, element),如果列表中已经存在元素,则将现有的元素右移一个位置,以便为新元素腾出空间。
- 插入后,列表的长度会增加被添加的元素数量。
因此,add(0) 方法用于单个元素的插入,而 addAll(0) 方法用于批量插入多个元素。
7、 String、StringBuffer、StringBuilder 的区别?
String、StringBuffer 和 StringBuilder 都是 Java 中用于处理字符串的类,它们之间的主要区别如下:
- 不可变性:
-
- String 类是不可变类,一旦创建,其值就不能被修改。每次对字符串进行操作(如拼接、替换等),都会创建一个新的 String 对象,原始对象不会发生改变。
- StringBuffer 和 StringBuilder 类是可变类,可以动态修改其值。
- 线程安全性:
-
- String 是线程安全的,因为它的值不可变,多个线程共享一个字符串实例时不会出现线程安全问题。
- StringBuffer 是线程安全的,它的方法被 synchronized 关键字修饰,保证了多线程环境下的线程安全性。
- StringBuilder 不是线程安全的,它的方法没有进行同步处理,所以在多线程环境下使用时需要自行处理同步问题。
- 性能:
-
- 当需要频繁进行字符串拼接操作时,建议使用 StringBuffer 或 StringBuilder,因为它们的可变性可以减少对象的创建和销毁开销,提高性能。
- StringBuffer 是 JDK 1.0 引入的,所有方法都是同步的,适用于多线程环境,但性能相对较低。
- StringBuilder 是 JDK 1.5 引入的,不是同步的,在单线程环境中使用性能更好。
综上所述,如果需要频繁修改字符串内容且在多线程环境下使用,建议使用 StringBuffer;如果在单线程环境下进行字符串操作,可以选择 StringBuilder;如果不需要修改字符串内容,或者是在多线程环境下共享字符串实例,可以使用 String。
8、如何实现数组和 List 之间的转换?
数组转 List:使用 Arrays. asList(array) 进行转换。
List 转数组:使用 List 自带的 toArray() 方法。
9、java序列化
Java 序列化是指将对象转换为字节流的过程,以便可以在网络上传输或者保存在文件中。序列化是一种常见的数据持久化和数据传输的方式,它可以实现对象的状态保存、跨网络传输等功能。
Java 提供了 java.io.Serializable 接口,通过实现这个接口,可以让对象支持序列化和反序列化操作。实现 Serializable 接口的类可以被称为是可序列化的。
要使用 Java 序列化,可以按照以下步骤:
- 实现 Serializable 接口:将需要序列化的类实现 Serializable 接口。这个接口没有定义任何方法,只是作为一个标记,表示该类可以进行序列化。
- 创建输出流:利用 ObjectOutputStream 类创建一个输出流,将对象序列化后写入到流中。
- 创建输入流:利用 ObjectInputStream 类创建一个输入流,从流中读取序列化后的对象。
需要注意的是,被序列化的类及其成员变量都必须是可序列化的。如果某个成员变量不希望被序列化,可以使用 transient 关键字进行标记,在序列化过程中将被忽略。
此外,还可以通过自定义序列化和反序列化方法来对对象的序列化和反序列化过程进行更加灵活的控制。可以在类中定义 writeObject() 和 readObject() 方法,实现对特定成员变量的序列化和反序列化操作。
总之,Java 序列化提供了一种方便的方式来实现对象的持久化和跨网络传输,但在使用时需要注意类的可序列化性以及对应的输入输出流的使用和关闭等细节。
10、线程
线程(Thread)是计算机中执行的最小单位,指在程序中独立运行的一段代码。线程是进程中的一个实体,一个进程可以包含多个线程,它们共享进程的资源。
在 Java 中,线程由 java.lang.Thread 类表示。使用线程可以实现并发执行,将任务分配给不同的线程同时运行,提高程序的执行效率和响应性。
Java 中创建线程的方式有两种:
- 继承 Thread 类:通过继承 Thread 类,并重写 run() 方法来定义线程的执行代码。
- 实现 Runnable 接口:通过实现 Runnable 接口,并实现 run() 方法来定义线程的执行代码。
线程的生命周期包括以下几个状态:新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、等待(Waiting)、定时等待(Timed Waiting)和终止(Terminated)。线程可以通过调用 start() 方法启动,在运行状态下执行 run() 方法中的代码逻辑,线程执行完成或者调用 stop() 方法后进入终止状态。
并发编程中需要注意多线程之间的同步与互斥,以避免竞态条件和数据不一致等问题。可以使用 synchronized 关键字、锁对象(如 ReentrantLock)、信号量(如 Semaphore)等机制保证线程安全。
此外,Java 还提供了一些线程间通信的机制,如等待-通知机制(通过 wait()、notify() 和 notifyAll() 方法实现),用于线程之间的协作和数据传递。
需要注意的是,在多核处理器上,并发执行的线程可能会引发线程安全问题,如竞争条件、死锁等。因此,多线程编程需要谨慎设计和使用,遵循线程安全的原则。
另外,Java中还有其他方式来创建线程,例如使用Callable和Future接口、线程池等,这些方式提供了更多的灵活性和控制能力,适用于不同的并发场景。
11、java线程池
Java 线程池是一种用于管理和复用线程的机制,它可以帮助开发人员更有效地管理和调度多线程任务。通过使用线程池,可以避免频繁创建和销毁线程的开销,并控制线程的数量和并发度,提高系统的性能和资源利用率。
Java 提供了内置的线程池实现,位于 java.util.concurrent
包下的 Executor
接口及其实现类,常用的线程池实现包括以下几种:
ThreadPoolExecutor
:ThreadPoolExecutor
是 Java 提供的最基础的线程池实现类。它允许开发人员根据需要自定义线程池的参数,如核心线程数、最大线程数、线程空闲时间等。Executors
:Executors
是一个工厂类,提供了一些静态方法用于创建常用的线程池,如newFixedThreadPool
(固定大小线程池)、newCachedThreadPool
(可缓存线程池)等。ScheduledThreadPoolExecutor
:ScheduledThreadPoolExecutor
是一个支持定时任务的线程池实现,它可以按照计划执行延迟任务或周期性任务。
使用线程池的基本步骤如下:
- 创建线程池对象:通过构造器或工厂方法创建相应的线程池实例。
- 提交任务:将需要执行的任务提交给线程池,可以使用
execute
方法或submit
方法。 - 线程池执行任务:线程池会自动调度线程来执行提交的任务。
- 关闭线程池:任务执行完毕后,应手动关闭线程池,释放资源。
线程池支持自动复用线程、线程回收、线程数量控制等特性。通过合理地配置线程池的参数,可以控制并发度、优化性能,并防止系统资源被过度消耗。
值得注意的是,在使用线程池时需要根据业务需求和系统负载进行合理配置。过小的线程池容易导致任务堆积,而过大的线程池可能会造成资源浪费。因此,应根据具体情况选择合适的线程池类型,并根据需求调整线程池的参数。
11、实例化及反射
在Java中,实例化是指创建一个类的对象。通过调用类的构造方法,可以在内存中分配一块空间来存储该类的对象,并初始化对象的成员变量。
要实例化一个类,可以使用new关键字后跟类名以及括号。
这将调用ClassName类的默认构造方法,为对象分配内存并初始化其成员变量。
反射是Java中的一种高级特性,它允许在运行时动态地获取类的信息并操作类的成员。通过反射,可以实现以下操作:
- 获取类的名称、包名以及修饰符。
- 获取类的构造方法、字段和方法。
- 动态调用类的方法。
- 创建类的对象。
要使用反射来实例化一个类,可以按照以下步骤进行操作:
- 获取类的Class对象。有三种常见的方式可以获取Class对象:
-
- 使用类名.class语法:Class<ClassName> clazz = ClassName.class;
- 调用对象.getClass()方法:Class<?> clazz = object.getClass();
- 使用Class.forName()方法:Class<?> clazz = Class.forName("ClassName");
- 利用Class对象获取类的构造方法:
parameterTypes是构造方法的参数类型列表(如果有参数),可以是多个参数以及其顺序。
- 通过构造方法对象创建类的实例:
12、Servlet的生命周期是由容器(例如Tomcat)来管理的,可以分为以下三个阶段:
- 初始化阶段(Initialization):当Servlet第一次被请求时,容器会创建该Servlet的实例,并调用其init()方法进行初始化。在该方法中,我们可以进行一些初始化操作,例如加载配置文件、建立数据库连接等。init()方法只会被调用一次,在Servlet的生命周期中起到初始化的作用。
- 请求处理阶段(Service):当有请求到达服务器时,容器会调用Servlet的service()方法来处理请求。在该方法中,我们编写处理请求的逻辑代码,例如读取请求参数、执行业务逻辑、生成响应等。service()方法会根据请求的类型(GET、POST、DELETE等)调用对应的doXxx()方法(例如doGet()、doPost()、doDelete()等)。每次请求都会调用service()方法,因此在该方法中完成的操作应该是无状态的。
- 销毁阶段(Destroy):当容器关闭或者重新部署Web应用时,会销毁Servlet实例,此时容器会调用Servlet的destroy()方法来进行清理操作。在该方法中,我们可以释放资源、关闭数据库连接等。destroy()方法只会被调用一次,在Servlet的生命周期中起到清理资源的作用。
需要注意的是,虽然Servlet的生命周期中定义了这些方法,但我们并非必须在每个方法中编写代码,通常情况下只需要在init()和destroy()方法中进行相关操作即可,而请求处理逻辑则应放在service()方法中或其对应的doXxx()方法中。
整个Servlet的生命周期由容器负责管理,我们只需要关注实现自己的业务逻辑即可。容器负责创建、初始化、调用和销毁Servlet实例,有效地将Servlet集成到Web应用中。
11、抽象类有构造器吗
抽象类可以有构造器(构造方法)。抽象类是一种特殊的类,它不能被实例化,但可以被继承。当我们从抽象类派生出具体的子类时,子类必须实现抽象类中定义的抽象方法。同时,子类也会继承抽象类的构造器。
抽象类的构造器遵循与普通类相同的规则,可以有参数、重载和访问修饰符。抽象类的构造器的作用是完成对象的初始化,可以在构造器中进行一些必要的操作,例如初始化成员变量、调用父类的构造器等。
12、JSP(JavaServer Pages)
JSP(JavaServer Pages)是Java的一种服务器端技术,它允许开发者在HTML页面中嵌入Java代码。在JSP中,有一些特殊的内置对象,这些对象提供了访问常用功能和信息的方法。以下是JSP中的内置对象:
- request:代表客户端的HTTP请求,可以通过该对象获取请求参数、请求头、会话信息等。
- response:代表服务器对客户端的HTTP响应,可以通过该对象设置响应头、响应内容等。
- out:代表JSP页面的输出流,可以通过该对象向客户端发送内容。
- session:代表用户的会话对象,可以通过该对象存储和获取与特定用户相关的数据,会话跟踪也是基于该对象实现的。
- application:代表整个Web应用程序的上下文对象,可以在不同的JSP页面之间共享数据。
- page:代表当前JSP页面本身,可以通过该对象调用页面定义的方法。
- exception:代表当前页面引发的异常对象,可以通过该对象获取异常信息。
13、线程死锁
线程死锁是多线程编程中的一种常见问题,当两个或多个线程彼此互相等待对方释放资源,而导致所有线程都无法继续执行时,就会发生死锁。
造成线程死锁的常见条件是:
- 互斥条件:至少有一个资源只能同时被一个线程占用。
- 请求和保持条件:一个线程已经持有了至少一个资源,在请求新的资源时又被阻塞,但仍继续持有已获取的资源。
- 不可剥夺条件:已经分配给一个线程的资源在未被该线程释放之前,不能被其他线程强行剥夺。
- 循环等待条件:存在一组等待线程,每个线程都在等待下一个线程所持有的资源。
当以上四个条件同时满足时,就可能导致线程死锁的发生。
解决线程死锁问题的一般方法包括:
- 避免死锁:设计良好的并发算法,避免出现死锁的条件。
- 资源有序分配:按照固定的顺序分配资源,避免线程循环等待。
- 加锁顺序的统一:所有的线程按照相同的顺序获取锁,避免不同线程之间因锁的获取顺序不同而导致死锁。
- 超时机制:当线程在一段时间内无法获取到所需的资源时,主动释放已持有的资源,避免长时间的相互等待。
- 死锁检测和恢复:通过算法检测死锁的发生,并采取相应的措施解除死锁状态。
在多线程编程中,理解和处理线程死锁是非常重要的,合理设计并发算法和避免死锁的发生,可以提高程序的性能和可靠性。
15、线程锁
线程锁是一种并发编程中用于保护共享资源或临界区的机制,它可以确保同一时间只有一个线程可以访问被锁定的代码块,从而避免多线程之间对共享资源的竞争和冲突。
在Java中,线程锁通常使用synchronized关键字来实现。Synchronized关键字可以标记一个方法或一个代码块,将其变为临界区(也称为互斥区),保证同一时间只有一个线程可以进入该区域执行代码。当一个线程进入临界区时,其他线程将被阻塞,直到该线程执行完临界区代码并释放锁。
16、设计模式
设计模式是在软件设计过程中用于解决常见问题的经验总结和最佳实践的一种思想体系。设计模式提供了一系列被证明有效的解决方案,帮助开发人员设计出可维护、可扩展、可重用的软件系统。
以下是一些常见的设计模式分类:
- 创建型模式(Creational Patterns):这些模式关注对象的创建机制,包括单例模式、工厂模式、抽象工厂模式、建造者模式和原型模式等。
- 结构型模式(Structural Patterns):这些模式关注类和对象如何组合形成更大的结构,包括适配器模式、装饰器模式、代理模式、组合模式、桥接模式、外观模式和享元模式等。
- 行为型模式(Behavioral Patterns):这些模式关注对象之间的通信和协作方式,包括观察者模式、模板方法模式、策略模式、命令模式、迭代器模式、状态模式、职责链模式和访问者模式等。
- 并发模式(Concurrency Patterns):这些模式关注多线程环境下的并发和同步问题,包括生产者消费者模式、读写锁模式、保护性暂停模式、信号量模式、线程池模式和管道过滤器模式等。
- 架构模式(Architectural Patterns):这些模式关注整个系统架构的设计和组织方式,包括MVC模式、MVP模式、MVVM模式、分层模式、微服务模式和领域驱动设计(DDD)等。
每种设计模式都有其特定的使用场景和优缺点,开发人员可以根据实际需求选择合适的设计模式来解决问题。同时,设计模式也可以提高代码的可读性和可维护性,促进团队协作和代码重用。然而,不应滥用设计模式,应根据具体情况权衡使用设计模式的成本和收益。
17、多线程访问对象
多项程访问对象(Multi-threaded Access Objects)是指在多线程环境下同时访问的对象。在多线程应用中,多个线程可能会同时对共享的对象进行读取和写入操作,因此需要特别注意多项程访问对象的线程安全性和数据一致性。
以下是一些处理多项程访问对象的常见方法:
- 使用同步机制:通过使用同步关键字(synchronized)或者重入锁(ReentrantLock)等同步机制,限制同一时间只有一个线程能够访问对象。这样可以确保在同一时刻只有一个线程对对象进行读写操作,从而保证线程安全性。但是需要注意,同步机制可能会引发线程竞争和性能问题,因此需要合理地使用同步机制。
- 使用线程安全的数据结构:选择线程安全的数据结构,如线程安全的集合类(ConcurrentHashMap、ConcurrentLinkedQueue)等,这些数据结构内部已经实现了线程安全机制,可以安全地在多线程环境下使用。
- 使用不可变对象:如果对象的状态在创建后不会发生变化,可以设计为不可变对象。不可变对象在多线程环境下是线程安全的,因为无需担心对象状态的改变。
- 使用原子操作:对于某些简单的操作或变量,可以使用原子操作类(AtomicInteger、AtomicLong、AtomicReference 等)。原子操作是线程安全的,可以实现无锁的并发访问。
- 合理的对象设计:通过合理的对象设计,减少多线程并发操作的需要。例如,使用分离的对象或设计模式,将不同线程的数据隔离开来,减少并发冲突的可能性。
无论采用哪种方法,都需要在开发过程中充分考虑多线程并发访问对象的线程安全性、数据一致性和性能问题。适当的选择和实现对多项程访问对象的操作方式将对整个系统的可靠性和性能产生重要影响。
18、字符串反转的方法
有多种方法可以实现字符串反转。以下是几种常见的方法:
- 使用StringBuilder或StringBuffer的reverse方法:
String original = "Hello, World!";
StringBuilder reversed = new StringBuilder(original).reverse();
String result = reversed.toString();
System.out.println(result); // 输出: !dlroW ,olleH
- 使用递归:
public static String reverseString(String str) {
if (str.isEmpty()) {
return str;
}
return reverseString(str.substring(1)) + str.charAt(0);
}
String original = "Hello, World!";
String result = reverseString(original);
System.out.println(result); // 输出: !dlroW ,olleH
- 使用字符数组:
public static String reverseString(String str) {
char[] charArray = str.toCharArray();
int start = 0;
int end = str.length() - 1;
while (start < end) {
char temp = charArray[start];
charArray[start] = charArray[end];
charArray[end] = temp;
start++;
end--;
}
return new String(charArray);
}
String original = "Hello, World!";
String result = reverseString(original);
System.out.println(result); // 输出: !dlroW ,olleH
请注意,以上示例中的方法是用Java语言实现的,但可以根据具体的编程语言和需求进行相应调整。
19、java垃圾回收机制
Java的垃圾回收机制是自动的,这意味着开发人员无需手动释放内存。Java虚拟机(JVM)通过垃圾回收器(Garbage Collector)来管理内存并回收不再使用的对象。
Java的垃圾回收机制基于以下原理:
- 引用计数:垃圾回收器追踪每个对象的引用计数。当一个对象被引用时,其引用计数增加;当引用被删除或超出作用域时,引用计数减少。当引用计数为0时,对象不再被引用,其空间可以被回收。
- 可达性分析:Java的垃圾回收器使用可达性分析算法来确定对象是否可达。从根对象(如活动线程、静态变量等)开始,垃圾回收器遍历对象引用链,标记所有可达的对象。对于未标记的对象,则被认为是不可达的,可以被垃圾回收器回收。
Java的垃圾回收器提供了不同的实现策略,如标记-清除(Mark and Sweep)、复制(Copying)、标记-压缩(Mark and Compact)等。这些垃圾回收策略根据应用程序的性质和内存需求选择最合适的方式。
在Java中,开发人员可以使用System.gc()
方法请求垃圾回收,但实际上并不能确保会立即执行垃圾回收操作。垃圾回收过程通常由JVM自动触发并在后台运行,以确保系统性能的平衡和最佳效率。
需要注意的是,垃圾回收机制能够自动管理内存,但并不意味着开发人员不需要关注内存使用。良好的内存管理实践包括避免内存泄漏、及时释放不再使用的对象等,以确保系统的健壮性和性能。
20、并发和并行
在计算机科学中,并发(Concurrency)和并行(Parallelism)是两个重要的概念,用于描述多个任务执行的方式。
并发是指多个任务在同一时间段内交替进行,每个任务按照一定的顺序和时间片执行,看起来好像是同时进行的。在并发编程中,任务之间可以相互切换,每个任务都可能等待其他任务的完成才能继续执行。这种方式可以提高系统的效率和资源利用率,并且通常用于解决同时处理多个任务或请求的场景。常见的并发编程模型包括多线程和事件驱动。
与此不同, 并行是指多个任务同时进行,同时占用多个处理器核心或计算资源,各个任务独立运行,各自处理不同的数据片段或子任务。在并行计算中,任务之间是同时进行的,无需等待其他任务的完成。这种方式可以显著提高计算性能和速度,常用于解决需要高度计算密集型操作的问题。常见的并行编程模型包括多进程和GPU计算。
简而言之,并发是指多个任务同时进行,但是通过时间片轮转进行切换;而并行是指多个任务同时进行,可以同时进行多个任务,无需相互等待。
要注意的是,并发和并行并不是互斥的概念。在实际应用中,往往会同时使用并发和并行的技术,以充分利用计算资源并提高系统的性能和响应能力。
21、用两种方式遍历出map集合的所有key和value
当需要遍历一个Map集合的所有键和值时,可以使用以下两种方式:
方式一:使用Map的keySet()方法遍历键,并通过键获取对应的值。
Map<K, V> map = ...; // 假设已经存在一个Map集合
for (K key : map.keySet()) {
V value = map.get(key);
// 处理键和值
// ...
}
在这种方式中,我们通过Map的keySet()方法获取所有的键的集合,然后通过循环遍历每个键,再通过键获取对应的值。缺点是在每次循环中需要进行两次查找操作,效率相对较低。
方式二:使用Map的entrySet()方法遍历键值对。
Map<K, V> map = ...; // 假设已经存在一个Map集合
for (Map.Entry<K, V> entry : map.entrySet()) {
K key = entry.getKey();
V value = entry.getValue();
// 处理键和值
// ...
}
在这种方式中,我们通过Map的entrySet()方法获取包含所有键值对的集合。这个集合中的每个元素都是一个Map.Entry对象,其中包含了键和值。通过循环遍历这个集合,可以直接获取每个键值对的键和值,避免了多次查找的开销,效率相对较高。
需要注意的是,以上两种方式都是通用的,无论何种编程语言都可以使用类似的方式来遍历Map集合的键和值。只需要将代码中的数据类型和语法适配到具体的编程语言即可。
22、请求转发和重定向
请求转发(Request Forwarding)和重定向(Redirection)是两种在网络应用中常见的技术,用于处理客户端请求的转发和跳转。
- 请求转发:
请求转发是指服务器接收到客户端的请求后,将该请求转发给另一个资源或处理程序来处理。服务器接收到请求后,根据一些条件(如请求路径、类型等)判断需要转发到哪个资源或处理程序上。这样,服务器将请求交给了其他的组件或程序进行处理,然后将处理结果再返回给客户端,客户端并不知道请求被转发到了其他的组件上。 - 重定向:
重定向是指服务器接收到客户端的请求后,返回一个特殊的响应,指示客户端重新发送请求到另一个指定的URL。服务器通过返回一个 HTTP 状态码(如 301 Moved Permanently 或 302 Found),以及一个新的 URL,告诉客户端将请求定向到新的位置。客户端收到响应后,会重新发送请求到新的 URL,实现跳转到其他页面或资源。
两者的区别在于:
- 请求转发是在服务器内部进行的,客户端并不知道请求被转发了;
- 重定向是由服务器返回响应给客户端,客户端收到响应后会重新发送请求到新的 URL。
使用场景:
- 请求转发通常用于在服务器内部的不同组件之间进行交互,实现复杂的请求处理逻辑,避免代码重复。
- 重定向常用于用户登录、注册、页面跳转等场景,可以引导用户访问其他页面或执行特定操作。
总体来说,请求转发和重定向都是在处理客户端请求时常见的技术手段,用于实现特定的需求和功能。具体要选择哪种方式取决于你的应用需求和实现方式的方便性。
23、poi
POI(Apache POI)是一个开源的 Java 库,用于处理 Microsoft Office 格式的文件,如 Excel、Word 和 PowerPoint 等。它提供了一组 API,可以读取、写入和操作这些 Office 文件,使得开发人员能够在 Java 应用程序中对这些文件进行生成、修改和解析等操作。
POI 库主要包含以下几个组件:
- HSSF:用于读写处理 Excel 文件(.xls 格式),支持 Excel 97-2003。
- XSSF:用于读写处理 Excel 文件(.xlsx 格式),支持 Excel 2007 及以上版本。
- SXSSF:用于处理大规模数据的 Excel 文件,以便在内存中保持较低的占用。
- HWPF:用于读写处理 Word 文件(.doc 格式),支持 Word 97-2003。
- XWPF:用于读写处理 Word 文件(.docx 格式),支持 Word 2007 及以上版本。
- HSLF:用于读写处理 PowerPoint 文件(.ppt 格式),支持 PowerPoint 97-2003。
- XSLF:用于读写处理 PowerPoint 文件(.pptx 格式),支持 PowerPoint 2007 及以上版本。
通过使用 POI 库,开发人员可以在 Java 应用程序中实现对 Excel、Word 和 PowerPoint 等文件的读取、创建、修改和操作等功能。例如,可以读取 Excel 文件中的数据、创建并写入新的 Excel 文件、将数据导出为 Excel 格式、从 Word 文件中提取文本内容等。
24、Easyexcel
EasyExcel 是一个基于 Apache POI 的开源 Java 库,专注于简化 Excel 文件的读写操作。它提供了更简单、更高效的 API ,使得开发人员能够轻松地在 Java 应用程序中进行 Excel 文件的读取和写入。
EasyExcel 的优点包括:
- 简单易用:EasyExcel 提供了简洁的 API,使得读写 Excel 文件变得更加简单和直观。开发人员可以使用少量的代码来实现读取和写入 Excel 中的数据,无需繁琐的操作和复杂的配置。
- 高性能:EasyExcel 底层使用了一套优化的读写算法,能够以较高的速度处理大规模的 Excel 文件。它减少了内存的使用,提高了处理速度和性能,特别适合处理大量数据的场景。
- 支持多种数据源:EasyExcel 可以读取和写入多种数据源,包括常见的 Java 对象、List 结构、Map 结构等。开发人员可以根据需要选择适合的数据源进行读写操作。
- 强大的功能扩展:EasyExcel 提供了丰富的功能扩展,例如数据转换、样式设置、单元格合并、图表生成等。开发人员可以根据实际需求定制操作和处理逻辑。
- 友好的错误处理:EasyExcel 提供了良好的错误处理机制,能够捕获和提示读写过程中的异常,便于开发人员进行错误处理和调试。
使用 EasyExcel 进行 Excel 文件的读写操作时,只需简单几步即可完成:
- 添加依赖:在项目的构建文件中添加 EasyExcel 的依赖,以引入 EasyExcel 库。
- 创建 ExcelWriter 或 ExcelReader 对象:根据需求选择创建 ExcelWriter(用于写入数据到 Excel)或 ExcelReader(用于从 Excel 读取数据)对象。
- 设置读写参数(可选):根据需要设置读写的参数,如文件路径、Sheet 名称、读写的起始位置等。
- 执行读写操作:通过调用相应的 API 方法,执行读取或写入 Excel 文件的操作。
- 关闭资源:在操作完成后,关闭相应的资源,释放内存和文件句柄。
25、重载重写
重载(Overloading)和重写(Overriding)是面向对象编程中的两个概念,用于描述不同的方法行为。它们的主要区别如下:
重载(Overloading):
- 在同一个类中,可以定义多个方法具有相同的名称,但参数列表不同(参数类型、参数个数或参数顺序不同)。
- 重载方法具有相同的方法名,但在编译时根据调用时提供的参数类型或个数来自动选择匹配的方法。
- 重载方法通常用于提供不同的方法签名和功能。
示例:
public class Calculator {
public int add(int x, int y) {
return x + y;
}
public double add(double x, double y) {
return x + y;
}
}
使用重载方法时,根据传入的参数类型自动选择匹配的方法:
Calculator calculator = new Calculator();
calculator.add(1, 2); // 调用 int add(int x, int y)
calculator.add(1.5, 2.5); // 调用 double add(double x, double y)
重写(Overriding):
- 在继承关系中,子类可以覆盖父类的方法,提供新的实现(方法体)来替代父类的方法。
- 重写方法具有相同的方法名、相同的参数列表和相同的返回类型。
- 重写方法用于改变继承而来的方法的实现,以适应子类的特殊需求。
示例:
public class Shape {
public void draw() {
System.out.println("画一个形状");
}
}
public class Circle extends Shape {
@Override
public void draw() {
System.out.println("画一个圆");
}
}
通过重写方法,子类可以改变父类方法的实现:
Shape shape = new Circle();
shape.draw(); // 调用 Circle 中重写的 draw() 方法,输出 "画一个圆"
总结:
重载是在同一个类中定义多个方法具有相同的名称但参数列表不同,目的是提供不同的方法签名和功能。重写是子类覆盖父类的方法,目的是改变继承而来的方法的实现。这两个概念在不同的场景中都有它们的用途。
二、spring、springmvc、springboot
1.谈谈你对Spring的理解?
Spring是一个开源的Java应用框架,它提供了一种轻量级的、非侵入式的编程模型,用于构建企业级应用程序和服务。以下是我对Spring的理解:
- 容器管理:Spring基于控制反转(IoC)的概念,通过容器(ApplicationContext)负责创建和管理对象的生命周期,实现了对象之间的解耦。开发者不需要手动管理对象的创建和销毁,而是通过配置将对象的创建交由Spring容器完成。
- 依赖注入:Spring支持依赖注入(Dependency Injection),即将对象的依赖通过配置或注解的方式注入到目标对象中,避免了硬编码和紧耦合的问题。这样可以使得组件之间的依赖关系更加清晰、灵活,并且方便进行单元测试和替换。
- 面向切面编程:Spring提供了面向切面编程(AOP)的支持,通过在不修改原代码的情况下,将跨越多个对象的通用功能(如事务管理、日志记录等)从业务逻辑中分离出来,提高了代码的可重用性和可维护性。
- 组件化和模块化:Spring鼓励开发者通过组件化的方式构建应用程序,使得各个模块可以独立开发、测试和部署。Spring提供了诸多组件(如数据访问、消息传递、安全认证等),可以灵活组合使用,以满足不同的业务需求。
- 集成其他框架:Spring对于集成其他框架和技术有很好的支持,例如与Hibernate、MyBatis等持久层框架的整合,与MVC框架的集成(如Spring MVC),以及与消息队列、缓存等外部服务的无缝集成。
- 测试支持:Spring提供了丰富的测试支持,包括基于JUnit的单元测试、模拟对象的创建和注入等,使得开发者能够方便地对应用程序进行单元测试和集成测试。
总的来说,Spring是一个强大而灵活的Java框架,它简化了企业级应用程序的开发,提供了一系列的特性和工具,帮助开发者构建可扩展、可维护和高效的应用程序。
2.谈谈你对IOC、AOP的理解?
IOC
IOC,即控制反转,把对象的创建、初始化、销毁交给 Spring 来管理,而不是由开发者控制,实现控制反转。IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂(BeanFactory 接口)。IOC的原理是基于xml解析、工厂设计模式、反射实现的。使用IOC可以降低代码的耦合度。
AOP(面向切面编程)是一种编程范式,它的核心概念是将应用程序的关注点分离。通过 AOP,我们可以将与主要业务逻辑无关但又经常存在于多个组件中的横切关注点(例如日志记录、事务管理、安全认证等)提取出来,并通过将它们称为“切面”来统一管理。
AOP 的关键思想是将这些横切关注点从原始对象中解耦出来,并通过在运行时动态地将这些切面织入到目标对象的方法调用中,实现对其进行增强或修改。这样,我们就能够避免在每个组件中重复编写相同的代码,同时也使得主要业务逻辑更加集中和清晰。
在 AOP 中,有三个主要的概念:
- 切面(Aspect):切面是一个模块化单元,用于将横切关注点的行为定义和封装起来。它由切点和通知组成。切点定义了在哪些连接点上应用特定行为,通知则定义了切面在特定切点执行的具体行为。
- 连接点(Join Point):连接点是应用程序运行过程中的特定点,例如方法调用或异常抛出。切面可以通过定义不同的切点来选择特定的连接点。
- 通知(Advice):通知是切面在连接点上执行的具体行为。常见的通知类型有前置通知(Before)、后置通知(After)、返回通知(AfterReturning)和异常通知(AfterThrowing)。不同的通知类型会在不同的时机触发,并插入到目标对象的方法调用流程中。
AOP 的优势在于它提供了一种在主业务逻辑之外关注横切关注点的方式,允许我们通过统一管理和配置切面来实现代码的重用性、可维护性和灵活性。Spring 框架中的 AOP 实现使用代理模式或字节码操作等技术,在运行时动态创建代理对象,将切面织入到目标对象的方法调用中。这种方式使得 AOP 的应用相对简单,可与其他 Spring 特性(如依赖注入)无缝集成,为构建复杂的企业应用程序提供了强大的支持。
3.什么是SpringBoot?它有什么优点?
Spring Boot 是一个开源的 Java 后端框架,它简化了基于 Spring 框架的应用程序的构建和部署过程。它提供了一种约定优于配置的方式,旨在帮助开发者快速启动和运行独立的、生产级别的 Spring 应用程序。
Spring Boot 的主要优点包括:
- 简化配置:Spring Boot 通过自动配置和约定大于配置的原则,减少了开发者对复杂 XML 配置的需求。它可以根据现有的类路径依赖项自动配置各种功能,并提供默认配置来满足绝大部分应用程序的需求。
- 快速启动:Spring Boot 提供了一组命令行工具,可以很方便地创建、运行和调试应用程序。它内置了一个嵌入式的 Servlet 容器(如 Tomcat 或 Jetty),使得应用程序可以直接以可执行的 JAR 包形式运行,而无需部署到外部服务器。
- 微服务支持:Spring Boot 具有与云和微服务架构良好的兼容性。它提供了一些特性和扩展,例如集成了 Spring Cloud 和 Netflix OSS 组件,能够简化微服务架构的开发和管理。
- 提高开发效率:Spring Boot 提供了大量的开箱即用的功能和库,如集成了常用的持久化框架(如 Spring Data JPA)、缓存组件(如 Redis)、消息队列(如 RabbitMQ)等。这样,开发者无需从零开始配置和集成这些组件,能够更快速地开发应用程序。
- 统一管理依赖:Spring Boot 使用 Maven 或 Gradle 来管理项目的构建和依赖关系。它提供了一个统一的依赖库,可以简化依赖的管理,并确保各个模块之间的版本兼容性。
总的来说,Spring Boot 通过简化配置、快速启动、微服务支持和开发效率等优点,大大减少了开发者的工作量,加快了应用程序的开发和部署速度,使得构建高质量的 Java 后端应用变得更加便捷和高效。
4、springboot常用注解
核心注解
● @SpringBootApplication:一个组合注解,包括@Configuration、@EnableAutoConfiguration和@ComponentScan。用于标注SpringBoot应用的主类,表示该类是SpringBoot应用的入口。
● @RestController:用于标识一个类是RESTful风格的控制器类,每个方法都返回一个对象,并且该对象会自动转换为JSON或者XML格式的数据。
● @Controller:用于标识一个类是控制器类。
● @Service:用于标识一个类是服务组件,表示该类提供一些业务逻辑操作。
● @Repository:用于标识一个类是数据访问组件,表示该类用于访问数据库或其他数据存储。
● @Component:用于指示普通的Spring Bean组件,将其声明为Spring上下文对象,并将其扫描在容器中。
● @Configuration:用于指定一个类是Spring的配置类,用于定义Bean、配置属性等。
● @Import:用于从其他配置类中导入Bean定义,可以在@Configuration类中引入其他Bean。
● @Profile:用于指定一个配置类在某个特定环境下才会生效,可以控制Bean的加载。
配置注解
● @ConditionalOnClass:用于判断类路径下是否有特定的类,只有当类路径下存在指定的类时,才会加载这个类。
● @ConditionalOnMissingBean:用于判断是否已经存在指定的Bean,如果已经存在指定的Bean,则不会加载这个类。
● @ConditionalOnWebApplication:用于判断当前应用是否是Web应用。
● @ConfigurationProperties:用于注入配置属性值,可以从配置文件中读取属性值,并将其注入到Bean对象的属性中。
● @EnableConfigurationProperties:用于启用@ConfigurationProperties注解。
● @Value:用于注入属性值,可以从配置文件中读取属性值,并将其注入到Bean对象的属性中。
● @Autowired:用于自动装配依赖项,会在Spring容器中查找匹配的Bean对象,并将其注入到当前类的属性中。
● @Qualifier:用于限定自动装配时Bean的名称。
部署注解
● @EnableAutoConfiguration:用于启用自动配置,SpringBoot会自动加载所需的配置。
● @EnableAsync:用于启用异步执行,可以提高应用的响应性能。
● @EnableScheduling:用于启用定时任务调度功能。
● @EnableWebMvc:用于启用SpringMVC功能。
● @EnableTransactionManagement:用于启用事务管理,可以对方法进行事务控制。
● @EnableJpaRepositories:用于启用Spring Data JPA功能。
测试注解
● @SpringBootTest:用于在测试中加载SpringBoot应用程序上下文,可以进行完整的端到端测试。
● @DataJpaTest:用于在测试中加载Spring Data JPA的上下文,可以进行JPA数据持久化相关的测试。
● @WebMvcTest:用于在测试中加载局部的Spring MVC应用程序上下文,可以测试MVC层的控制器类。
● @AutoConfigureMockMvc:用于自动配置MockMvc对象。
● @MockBean:用于创建模拟对象。
数据库注解
● @Transactional:用于添加事务操作。
● @Entity:用于标识一个类是实体类。
● @Table:用于指定实体类映射的表名。
● @Column:用于指定实体类属性对应的数据库列名。
● @Id:用于指定实体类属性为主键。
● @GeneratedValue:用于指定主键的生成策略
5、springboot读取外部的配置文件
1,在springboot的启动类上面追加 @ImportResource("classpath:spring.xml")
2, 可以同时加载多个配置配件
@ImportResource(locations ={"xxx1.xml","xxx2.xml"})
or
@ImportResource("classpath*:spring*.xml")
6、在Spring Boot中,可以通过使用@Value注解或@ConfigurationProperties注解来读取配置文件。
- 使用@Value注解:
-
- 在需要读取配置的类中,使用@Value注解标记对应的字段。
- 在注解中使用${}表达式指定配置文件中的属性键名。
- Spring Boot会将配置文件中对应属性的值注入到被@Value注解标记的字段中。
- 使用@ConfigurationProperties注解:
-
- 创建一个与配置文件对应的配置类,在该类中定义需要读取的属性字段,并提供相应的getter和setter方法。
- 使用@ConfigurationProperties注解标注配置类,并指定配置文件中的属性前缀。
- Spring Boot会自动将配置文件中以指定前缀开头的属性值注入到对应的配置类字段中。
在上述示例中,${myapp.name}是配置文件中的属性键名,appName字段使用@Value注解标记,并被注入了对应的属性值。通过调用displayAppName()方法,可以输出读取到的应用名称。
7、Mybais常用注解
Spring常用注解
@Component:泛指各种组件
@Controller、@Service、@Repository都可以称为@Component。
@Controller:控制层
@Service:业务层
@Repository:数据访问层
@Mapper 是 MyBatis 框架中的注解,用于将 Java 接口与对应的 SQL 映射文件进行绑定,实现数据库操作的映射关系。
@EnableTransactionManagement 来开启注解驱动的事务管理。
@Transactional 注解可以应用在方法级别或类级别上。在方法级别上使用时,只有被注解的方法会受到事务管理的影响;在类级别上使用时,该类中的所有公共方法都会受到事务管理的影响。
8、springmvc常用注解
- @Controller:用于标识一个类为处理器(Controller),处理用户请求并返回响应。
- @RequestMapping:用于映射请求路径和方法,指定处理器方法对应的URL路径。
- @GetMapping:用于将HTTP GET请求映射到处理器方法。
- @PostMapping:用于将HTTP POST请求映射到处理器方法。
- @PutMapping:用于将HTTP PUT请求映射到处理器方法。
- @DeleteMapping:用于将HTTP DELETE请求映射到处理器方法。
- @RequestParam:用于获取请求参数的值,并将其绑定到方法的参数上。
- @PathVariable:用于获取URL路径中的占位符变量,并将其绑定到方法的参数上。
- @RequestBody:用于接收HTTP请求的请求体,并绑定到方法的参数上,常用于处理JSON数据或表单提交。
- @ResponseBody:用于将方法返回的对象作为HTTP响应的内容发送给客户端,常用于返回JSON数据或其他格式的数据。
- @ModelAttribute:用于将方法的返回值或方法参数绑定到模型中,使其可以在视图中使用。
- @Valid:用于标记需要进行参数校验的方法参数,配合校验注解(如@NotNull、@NotBlank等)使用。
- @ExceptionHandler:用于定义异常处理方法,当发生指定类型的异常时,将调用该方法进行处理。
- @SessionAttributes:用于将模型中的特定属性存储在会话中,以便多个请求之间共享数据。
- @InitBinder:用于配置WebDataBinder,用于自定义数据绑定和格式化规则
9、springmvc工作流程
1、 用户向服务端发送一次请求,这个请求会先到前端控制器DispatcherServlet(也叫中央控制器)。
2、DispatcherServlet接收到请求后会调用HandlerMapping处理器映射器。由此得知,该请求该由哪个Controller来处理(并未调用Controller,只是得知)
3、DispatcherServlet调用HandlerAdapter处理器适配器,告诉处理器适配器应该要去执行哪个Controller
4、HandlerAdapter处理器适配器去执行Controller并得到ModelAndView(数据和视图),并层层返回给DispatcherServlet
5、DispatcherServlet将ModelAndView交给ViewReslover视图解析器解析,然后返回真正的视图。
6、DispatcherServlet将模型数据填充到视图中
7、DispatcherServlet将结果响应给用户
10、MVC是什么 分别代表什么
MVC是一种软件设计模式,用于组织应用程序的结构。它将应用程序分为三个主要组件:模型(Model)、视图(View)和控制器(Controller)。
- 模型(Model):模型表示应用程序中的数据和业务逻辑。它负责处理数据的存储、读取和处理,以及执行业务逻辑的操作。模型通常是应用程序的核心部分,它封装了应用程序的状态和行为。
- 视图(View):视图负责向用户展示模型中的数据,以及接收用户的输入。它将数据渲染成可视化的界面,如图表、表单、网页等。视图通常是与用户交互的界面部分,它将模型中的数据呈现给用户,并接收用户的输入,以便触发相应的行为。
- 控制器(Controller):控制器协调模型和视图之间的交互。它接收用户的输入并根据用户的请求来更新模型的状态或调用模型的操作。控制器还负责将模型中的数据传递给视图进行展示。它是用户与应用程序之间的桥梁。
11、servlet生命周期
Servlet的生命周期包括加载和实例化、初始化、服务和销毁这几个阶段。其中,初始化和销毁只会发生一次,而服务阶段会在每个请求到达时被调用。开发人员可以重写Servlet的init()、service()和destroy()方法,来实现自己的业务逻辑、处理请求和资源释放等操作。
12、在Java Servlet开发中,有以下几种常见的扩展机制及其用途
- Servlet:Servlet是一种基于Java的服务器端组件,用于处理客户端的HTTP请求并生成响应。通过实现Servlet接口或继承GenericServlet或HttpServlet类,开发人员可以自定义Servlet,实现灵活的业务逻辑处理。
- JSP:JavaServer Pages(JSP)是一种基于Java的模板引擎技术,用于将动态内容与静态的HTML页面进行混合。通过在JSP页面中编写Java代码和嵌入表达式,开发人员可以实现动态生成内容,并交给Servlet进行后续处理。
- Filter:过滤器(Filter)是一种可以拦截Servlet请求和响应的组件,用于对请求和响应进行预处理和后处理。开发人员可以通过实现Filter接口来创建过滤器,实现诸如身份验证、日志记录、数据转换等功能。
- Listener:监听器(Listener)是一种用于监听Servlet容器事件的组件,通过实现特定的监听器接口来响应容器事件。监听器可以用于捕获应用程序的启动、停止、会话创建和销毁等事件,从而实现相应的业务逻辑或资源管理。
- Interceptor:拦截器(Interceptor)是一种可以拦截和处理请求的组件,用于在请求处理的前后执行特定的逻辑。通常在Web框架中使用,拦截器可以用于权限验证、日志记录、性能监控等,提供更细粒度的请求处理控制。
13、bean的依赖注入
在面向对象编程中,依赖注入(Dependency Injection,DI)是一种实现对象之间解耦的技术。在Java中,依赖注入通常通过使用框架(如Spring)实现,其中最常见的方式是通过Bean的依赖注入。
Bean的依赖注入是指将一个对象作为另一个对象的依赖,通过在运行时将依赖对象注入(传递)给它,而不是在代码中直接创建依赖对象。这样可以实现对象之间的解耦和灵活性,并支持可维护性和可扩展性。
在Java中,依赖注入可以通过以下方式实现:
1. 构造函数注入(Constructor Injection):通过在类的构造函数中声明依赖参数,框架会在创建对象时自动将依赖对象传入构造函数。
2. Setter方法注入(Setter Injection):通过在类中定义setter方法,并在类中声明依赖属性,框架会在创建对象后,调用相应的setter方法来注入依赖对象。
3. 接口注入(Interface Injection):通过在类中定义接口类型的属性,并在类中声明依赖属性,框架会通过调用类实现的接口方法来注入依赖对象。
Spring框架是使用最广泛的实现依赖注入的框架之一。在Spring中,可以使用注解(如@Autowired、@Resource)、XML配置文件或Java配置等方式来实现依赖注入。通过配置框架,可以对Bean进行管理和注入,以实现对象之间的依赖关系。
通过依赖注入,可以实现对象之间的松耦合,提高代码的可测试性和可维护性。它还可以支持类的重用和组件的替换,减少代码的耦合度,并提高系统的灵活性。
4.注解注入@Autowired 与@Resource
14、@Autowired 与@Resource的区别
@Autowired和@Resource是Java中常用的依赖注入注解,它们可以用于将依赖对象自动注入到其他对象中,但有一些区别:
- 来源不同:
-
- @Autowired是Spring框架提供的注解,通过类型进行自动装配。它根据类型在容器中查找匹配的Bean进行注入。
- @Resource是JavaEE规范提供的注解,根据名称进行自动装配。它可以根据名称匹配容器中的Bean进行注入。
- 注入方式不同:
-
- @Autowired可以作用在成员变量、构造函数、Setter方法上,可以按照类型进行注入。它默认要求依赖对象必须存在,如果找不到匹配的Bean会抛出异常。
- @Resource可以作用在成员变量、构造函数、Setter方法上,可以按照名称进行注入。它可以指定依赖对象的名称,如果找不到匹配的Bean会尝试按照类型进行注入。
- 支持的容器不同:
-
- @Autowired是Spring框架的注解,只能在Spring容器中使用。
- @Resource是JavaEE规范的注解,可以在JavaEE容器中使用,也可以在Spring中使用。在Spring中,它会被当作@Autowired的替代品。
总的来说,@Autowired和@Resource都可以实现依赖注入,但@Autowired更常用于Spring框架中,通过类型进行注入,而@Resource是JavaEE规范提供的注解,通过名称进行注入。如果是在Spring环境中,建议使用@Autowired来实现依赖注入。
15、springmvc接受参数的方式
1、传统方式 HttpServletRequest 接收请求参数
2、RestFul方式 @RequestParam 接收请求参数
3、普通方式
4、对象方式
16、PageHelper是一个用于MyBatis的分页插件,它提供了简单易用的分页功能。PageHelper的原理如下:
-
- 拦截器:
PageHelper使用MyBatis的插件机制,通过拦截器拦截Executor的查询方法,实现对分页查询的拦截和处理。 - 参数解析:
当执行带有分页参数的查询方法时,PageHelper会解析参数中的分页参数(如页码和每页条数),并根据这些参数计算出查询的起始行和结束行。 - SQL重写:
PageHelper会根据起始行和结束行的值,通过修改原始的SQL语句,添加对应的分页查询语句。一般是使用LIMIT或ROWNUM等数据库特定的语法来实现分页。 - 总数查询:
在进行分页查询之前,PageHelper会执行一个额外的总数查询来获取满足条件的总记录数。这可以通过MyBatis的拦截器机制,在执行查询之前执行一个额外的查询来实现。 - 结果封装:
执行分页查询后,PageHelper会将查询结果封装到一个Page对象中,该对象包含分页相关的信息,如当前页码、每页条数、总记录数、总页数等。 - 总体来说,PageHelper通过拦截器机制,在执行查询前后对SQL进行修改和增强,以实现分页查询功能。它使用参数解析、SQL重写和总数查询等技术,对分页查询进行处理,并将结果封装到一个Page对象中,便于使用。
- 需要注意的是,PageHelper仅对使用了PageHelper提供的分页方法的查询生效,对于手动编写的SQL语句需要手动进行分页。同时,PageHelper还提供了一些可选的配置项,如自动获取总数、启用合理化等,以适应不同的需求。
- 拦截器:
17、springcould
Spring Cloud 是一套在 Spring 生态系统基础上构建的分布式系统开发工具包,它提供了丰富的组件和工具,用于快速开发和部署分布式系统的各个模块。
Spring Cloud 提供了多个功能模块,包括以下几个主要组件:
- 服务注册与发现(Service Discovery):通过集成服务注册中心(如 Eureka、Consul、Zookeeper等),实现服务的自动注册与发现,实现服务间的动态调用和负载均衡。
- 服务调用(Service Invocation):通过集成 RestTemplate 或 Feign,实现服务间的远程调用,简化了跨服务的 HTTP 通信。
- 服务熔断与容错(Circuit Breaker and Fault Tolerance):通过集成 Netflix Hystrix 或 Resilience4j,实现服务间的熔断、降级和故障转移,增加系统的稳定性和容错性。
- 分布式配置中心(Distributed Configuration):通过集成 Spring Cloud Config,实现配置的集中管理和动态刷新,避免了修改配置文件重新部署的麻烦。
- 服务网关(API Gateway):通过集成 Spring Cloud Gateway 或 Netflix Zuul,实现对外统一的 API 入口和请求的路由、过滤、鉴权等功能。
- 分布式消息机制(Messaging):通过集成 Spring Cloud Stream,实现基于消息的异步通信,并支持各种消息中间件(如 RabbitMQ、Kafka 等)。
- 分布式跟踪与链路追踪(Distributed Tracing):通过集成 Sleuth 和 Zipkin,实现分布式系统的调用链路跟踪和监控,方便进行性能分析和故障排查。
上述组件只是 Spring Cloud 提供的一部分功能,还有很多其他的组件和工具,如分布式锁、分布式任务调度、分布式会话管理等。Spring Cloud 提供了丰富的功能和抽象,使得开发者可以更加方便地构建和管理分布式系统。同时,Spring Cloud 还紧密集成了 Spring Boot,让开发者可以使用简洁的配置和注解来快速搭建微服务架构。
18、springdata
Spring Data 是 Spring 生态系统中用于简化数据库访问的一组项目。它提供了通用的 API 和与数据库交互的工具,使得开发者可以更轻松地进行数据访问和持久化操作。
Spring Data 提供了对各种数据存储技术的支持,包括关系型数据库(如 MySQL、PostgreSQL、Oracle 等)、NoSQL 数据库(如 MongoDB、Redis、Elasticsearch 等)、图数据库、列存储数据库等。
Spring Data 的主要目标是提供统一的编程模型,简化数据访问层的开发过程。它通过以下几个子项目实现这一目标:
- Spring Data JPA:为基于 Java Persistence API(JPA)的数据访问提供支持。简化了 JPA 的使用,提供了强大的查询功能和自动生成的 Repository 接口。
- Spring Data JDBC:提供了对基于关系型数据库的 JDBC 访问的支持。相比于传统的 ORM 框架,Spring Data JDBC 更加轻量级,关注于简化 SQL 操作和提供模板类,让开发者能够更直接地与数据库交互。
- Spring Data MongoDB:为 MongoDB 数据库提供支持。它基于 MongoDB 的 Java 驱动程序,并提供了一套简洁的 API,方便进行文档操作和查询。
- Spring Data Redis:提供了对 Redis Key-Value 存储系统的支持。它可以使用 RedisTemplate 或者注解驱动来操作 Redis 数据。
除了以上几个主要的子项目,Spring Data 还支持其他各种数据库和存储技术,如 Spring Data for Apache Cassandra、Spring Data for Elasticsearch 等。
Spring Data 的优点在于它提供了一种统一的编程模型,简化了数据访问层的开发,减少了样板代码的编写。同时,它还提供了灵活且强大的查询功能,支持动态查询和自定义查询方法的定义。通过 Spring Data,开发者可以更专注于业务逻辑的实现,而不用过多关注底层的数据访问细节。
19、如何修改缓存数据
要修改缓存数据,通常有以下几种方式:
- 直接更新缓存:如果你有对缓存数据的修改操作,可以直接更新缓存中对应的数据。具体操作取决于所使用的缓存技术和框架。例如,使用 Spring Cache 组件,可以使用
@CachePut
注解来更新缓存中的数据。 - 删除缓存:如果更新后的数据发生了变化,你可以选择删除缓存中对应的数据,下次请求时会重新加载最新的数据。通常可以使用
@CacheEvict
注解来删除缓存数据。 - 自动过期或失效:有些缓存技术支持自动过期或失效,即在一定时间内缓存数据会自动过期,下次请求时会重新加载最新的数据。你可以在缓存配置中设置过期时间或失效策略。例如,在使用 Redis 缓存时,可以配置数据的过期时间。
需要注意的是,修改缓存数据可能会引起数据一致性的问题。如果缓存被用于读多写少的场景,更新数据时应该同时更新数据库或其他持久存储,并确保缓存和数据库的数据保持一致。否则,可能会导致缓存和数据库数据不一致,引发脏读等问题。
此外,修改缓存数据时还需要考虑多节点部署的情况。如果系统有多个节点,并且每个节点都有自己的缓存副本,那么要保证修改后的数据在所有节点上都一致,需要进行缓存的清理或者使用分布式缓存技术,如 Redis 集群模式或者 Memcached。
总结来说,修改缓存数据需要根据具体场景选择适当的方式,同时考虑数据一致性和多节点部署的情况。
20、RBAC
RBAC 是 Role-Based Access Control(基于角色的访问控制)的缩写。它是一种访问控制机制,常用于网络安全领域,用于管理和限制用户对系统资源的访问。RBAC 基于角色进行授权,以帮助管理员和系统管理者更好地组织和管理用户权限。
在 RBAC 中,用户被分配到不同的角色,而每个角色都有特定的权限。这样,系统管理员可以通过为用户分配适当的角色来控制他们对系统资源的访问。RBAC 提供了一种灵活且可扩展的方法来管理访问控制,同时也可以降低管理复杂性。
RBAC 的关键概念包括角色、权限和用户。角色定义了一组相似权限的集合,权限定义了允许或禁止用户对资源执行的操作,而用户则被分配到一个或多个角色。
RBAC 在许多应用中都得到了广泛应用,尤其是在企业级系统和网络安全中。它提供了一种有效的方法来控制和管理用户访问权限,从而提高系统的安全性和可管理性。
21、文件上传
文件上传是指将本地计算机上的文件发送到远程服务器或应用程序的过程。这是一种常见的操作,用于许多互联网应用和系统中,例如网站上的头像上传、文件共享平台等
文件上传可以通过以下步骤完成:
- 客户端选择文件:用户在客户端(例如网页浏览器)上选择需要上传的文件。通常,使用
<input type="file">
标签来创建文件选择框。 - 准备上传请求:客户端通过HTTP协议构建一个上传请求。该请求包括一个特定的URL(上传目标),请求方法(通常为POST),以及必要的标头和其他相关信息。
- 发送上传请求:客户端将上传请求发送到服务器。这可以通过表单提交、Ajax、Fetch等方式进行。
- 服务器接收请求:服务器接收到客户端的上传请求。它可以通过处理HTTP请求来解析请求的内容和元数据。
- 处理文件上传:服务器端处理文件上传。这包括验证上传的文件类型、大小、权限等。一旦完成验证,可以将文件保存到指定的位置,或进行其他特定的处理,例如生成缩略图、存储文件元数据等。
- 响应上传结果:服务器生成一个响应,将其发送回客户端。该响应可能包含上传成功或失败的消息,以及其他相关信息。
文件上传时需要考虑以下几点:
- 文件大小限制:需要限制上传文件的大小,以避免服务器资源过度占用和网络传输效率低下。通常会在客户端和服务器端进行限制。
- 文件类型验证:可以对上传的文件进行类型验证,仅接受特定类型的文件。这可以帮助防止恶意文件上传和系统安全问题。
- 文件存储和命名:需要确定文件在服务器上的存储位置和命名方式。这可以根据应用的需求和组织结构来确定最佳实践。
- 安全性考虑:上传文件可能存在安全风险,例如文件注入、恶意代码等。应对这些风险进行适当的防范措施,例如对上传文件进行严格的验证和过滤。
以上是文件上传的一般过程和一些考虑事项。具体的实现方式会根据应用程序和技术选择的不同而有所差异。
22、webupload
WebUploader 是一个基于 HTML5 的文件上传组件,在 Web 开发中常用于实现大文件上传、断点续传、图片压缩等功能。它提供了丰富的 API 和事件处理机制,适用于各种浏览器和平台。
WebUploader 提供了以下主要特性:
- 多文件上传:可以同时上传多个文件,减少用户等待时间。 通过配置项 fileNumLimit 可以限制最大可选择的文件数量。
- 断点续传:支持上传大文件时的断点续传,能够在网络连接中断后恢复上传。
-
- 下面是使用 WebUploader 实现断点续传的基本步骤:
-
-
- 启用分片上传:在 WebUploader 的初始化配置项中,设置 chunked: true 来启用分片上传功能。分片上传会将文件切分为多个片段进行上传。
- 配置分片大小和并发数:使用配置项 chunkSize 来设置每个片段的大小,使用配置项 threads 来设置同时并发上传的片段数。可以根据实际情况进行调整,以平衡上传速度和服务器负载。
- 生成文件唯一标识:通过监听 WebUploader 的 uploadBeforeSend 事件,在上传之前生成一个唯一的文件标识(如文件的 MD5 值),并将其存储于后端服务器。
- 判断服务器中是否存在已上传的片段:在启动上传之前,通过向后端发送文件标识,判断服务器上是否已经存在该文件的片段。如果存在,则可以跳过已上传的片段,从下一个片段开始继续上传。
- 续传中断的片段:如果上传中断,可以通过监听 WebUploader 的 uploadError 事件,从中获取上传失败的片段信息,并记录已上传的片段重新上传。
- 后端处理:后端服务器需要实现上传接收接口,接收分片数据并保存到临时或指定位置。当所有分片上传完成后,服务器将分片合并为完整文件。
- 上传完成:在 WebUploader 的 uploadSuccess 事件中,通过判断所有分片是否上传完成,可以执行各种后续操作,如合并分片、保存文件信息等。
-
- 文件压缩与预览:支持图片文件的压缩上传,并提供预览功能,可以在用户选择文件后即时显示预览效果。
- 进度提示:通过进度条和事件处理,可以实时显示文件上传的进度。
- 文件验证与过滤:可以对文件进行类型验证和大小限制,防止上传非法文件。通过配置项 accept 和 fileSingleSizeLimit 可以设置文件类型和大小限制。
WebUploader 可以与各种服务器端语言(如 PHP、Java、Node.js 等)进行配合使用,实现文件的接收、处理和存储。它提供了详细的文档和示例代码,方便开发人员进行集成和使用。
使用 WebUploader 开发文件上传功能的步骤通常包括:
- 引入 WebUploader 库和相关依赖:在 HTML 页面中引入 WebUploader 的 JavaScript 和 CSS 文件,并确保依赖的库已正确加载。
- 创建一个上传按钮或拖拽区域:在页面上创建一个用于触发文件选择的按钮或拖拽上传区域。
- 初始化 WebUploader:通过 JavaScript 代码初始化 WebUploader 实例,设置相关配置项,如上传的 URL、允许的文件类型、文件大小限制等。
- 处理 WebUploader 事件:通过监听各种 WebUploader 事件,处理文件上传过程中的进度、成功、失败等情况,更新界面和进行后续操作。
- 后端处理:在服务器端接收和处理上传的文件,根据需求进行存储、处理或其他操作。
以上是 WebUploader 的基本使用过程,具体的实现细节可以参考 WebUploader 官方文档或相关教程。
23、MultipartFile[]后端处理文件上传时接收多个文件的数组
MultipartFile[]
是一个数据类型,通常用于在后端处理文件上传时接收多个文件的数组。在 Java 的 Spring 框架中,MultipartFile
是用于处理文件上传的接口,MultipartFile[]
则是一个由多个 MultipartFile
对象组成的数组,用于接收多个上传的文件。
使用 MultipartFile[]
可以方便地处理同时上传多个文件的情况。通过遍历 MultipartFile[]
数组,可以逐个获取每个文件的相关信息和数据。每个 MultipartFile
对象都提供了一些常用的方法,如 getOriginalFilename()
获取上传文件的原始文件名,getSize()
获取文件的大小,getInputStream()
获取文件的输入流等。
以下是使用 MultipartFile[]
进行文件上传的基本步骤:
- 在接收文件上传的后端方法中,使用
MultipartFile[]
作为参数来接收上传的文件。例如:
public String handleUpload(@RequestParam("files") MultipartFile[] files) {
// 文件上传处理逻辑
// ...
}
- 遍历
MultipartFile[]
数组,处理每个上传的文件。可以使用循环来遍历数组,例如:
for (MultipartFile file : files) {
String fileName = file.getOriginalFilename();
long fileSize = file.getSize();
// 其他文件处理逻辑
// ...
}
- 根据需求进行文件保存、处理或其他操作。根据文件的相关信息,可以将文件保存到指定位置,或进行其他特定的处理,例如生成缩略图、存储文件元数据等。
需要注意的是,文件上传时需要进行合适的错误处理和校验。可以通过判断文件大小、文件类型等进行验证,并处理上传过程中可能出现的异常。
总结来说,MultipartFile[]
是一个用于接收多个上传文件的数组,可方便地批量处理文件上传。使用 MultipartFile[]
可以获取每个文件的相关信息和数据,进行相应的处理和操作。具体的文件上传处理逻辑会根据后端框架和业务需求的不同而有所差异。
三、前端
1.通过vue怎么把前端的值发送到后端
使用Axios等HTTP请求库
2.vue怎么获取到后端的值
通过response.data获取后端返回的数据
3.vue获取的值怎么显示在页面上
- 使用插值表达式将获取的值直接嵌入到HTML模板中:{{}}
- 使用计算属性对获取的值进行处理,并将处理结果显示在页面上
- 使用指令绑定将获取的值赋给特定的属性
4.vue常用指令
Vue中有许多常用的指令可以用于操作DOM、处理事件、条件渲染、列表渲染等。以下是一些常用的Vue指令:
- v-bind(缩写为冒号:):用于动态绑定属性,将表达式的值赋给元素的属性。 示例:<img v-bind:src="imageUrl">
- v-model:用于在表单元素上双向绑定数据,实现数据的输入和响应变化。 示例:<input v-model="name">
- v-on(缩写为@):用于绑定事件监听器,触发指定方法或内联表达式。 示例:<button v-on:click="handleClick">
- v-if:根据条件判断是否渲染元素,如果条件为假,则不生成相应的DOM。 示例:<div v-if="showMessage">Hello, Vue!</div>
- v-show:根据条件显示或隐藏元素,通过样式控制元素的可见性。 示例:<div v-show="isVisible">This is a visible element.</div>
- v-for:用于循环渲染数组或对象的内容,并生成对应的多个元素。 示例:<li v-for="item in items">{{ item }}</li>
- v-text:将表达式的值作为文本内容进行插值。 示例:<span v-text="message"></span>
- v-html:将表达式的值作为HTML内容进行插值,可以解析HTML标签。 示例:<div v-html="htmlContent"></div>
以上是一些常用的Vue指令,可根据需要灵活运用。此外,Vue还有其他更多的指令和功能,你可以参考Vue的官方文档以获取更详细的信息和用法示例。
5、跨域
前端解决方案
1.使用JSONP方式实现跨域调用;
2.使用NodeJS服务器做为服务代理,前端发起请求到NodeJS服务器, NodeJS服务器代理转发请求到后端服务器;
后端解决方案
1、nginx反向代理解决跨域
2、服务端设置Response Header(响应头部)的Access-Control-Allow-Origin
3、在需要跨域访问的类和方法中设置允许跨域访问(如Spring中使用@CrossOrigin注解);
4、继承使用Spring Web的CorsFilter(适用于Spring MVC、Spring Boot)
5、实现WebMvcConfigurer接口(适用于Spring Boot)
6、GET和POST区别
GET和POST是HTTP协议中最常用的两种请求方法,它们在以下几个方面有所不同:
- 数据传输位置:GET方法通过URL的查询字符串将数据附加在URL中,即将数据放在请求的URL参数中;而POST方法通过请求的主体中传输数据,数据不会暴露在URL中。
- 安全性:GET请求的参数会暴露在URL中,因此对于敏感信息,如密码等,不适合使用GET方法;POST请求的参数在请求主体中,相对于GET请求更安全。
- 数据长度限制:GET请求对传输的数据长度有限制,不同浏览器和服务器有不同的限制;POST请求没有固定的长度限制,可以传输大量的数据。
- 缓存:GET请求可被缓存,浏览器会缓存GET请求的响应结果;POST请求无法被缓存,每次请求都需要从服务器获取响应。
- 幂等性:GET请求是幂等的,即多次执行相同的GET请求,不会对服务器资源产生影响;POST请求不是幂等的,多次执行相同的POST请求可能会产生不同的结果。
- 使用场景:GET请求适合获取资源,不会对服务器数据产生修改;POST请求适合提交数据到服务器,对服务器数据做修改或创建新的资源。
总的来说,GET方法适用于获取数据,对数据的修改操作应使用POST方法。GET方法传输数据简单、速度较快,而POST方法更注重数据的安全性和完整性。在使用时需要根据具体的需求和场景选择合适的请求方法。
7、网络连接的七层模型
- 物理层(Physical Layer):
物理层是最底层的层级,负责在物理媒介上传输原始的比特流。它处理物理连接、电压和位传送等细节。 - 数据链路层(Data Link Layer):
数据链路层负责将原始的比特流转换为数据帧,并提供可靠的数据传输。它处理帧的定界、错误检测和纠正,以及流控制等功能。 - 网络层(Network Layer):
网络层负责实现不同网络之间的数据传输,包括路由选择、寻址和路由器的转发。它将数据分割为更小的包,并通过网络路由选择将它们传递到目标节点。 - 传输层(Transport Layer):
传输层提供端到端的可靠通信,负责将数据从一个应用程序传输到另一个应用程序。它管理数据传输的可靠性、顺序性和流量控制,并提供错误检测和重传机制。 - 会话层(Session Layer):
会话层管理应用程序之间的通信会话,负责建立、维护和结束会话。它处理会话的开始、同步、检查点和恢复等功能。 - 表示层(Presentation Layer):
表示层负责数据的格式化、加密和解密,以确保不同系统之间的数据传输和解释的兼容性。它处理数据的压缩、加密、编码和格式转换。 - 应用层(Application Layer):
应用层是最高层的层级,提供用户直接使用的网络服务和应用程序。它包括各种网络应用,如电子邮件、文件传输、远程登录等。
8、tcp的三次握手
- 第一次握手(SYN):
客户端向服务器发送一个连接请求报文段,其中设置SYN标志位为1,同时选择一个初始的序列号(Seq)并发送。这个报文段的目的是告诉服务器,客户端请求建立连接。 - 第二次握手(SYN + ACK):
服务器接收到客户端的连接请求后,产生一个新的序列号(Seq2),设置SYN和ACK标志位均为1,将新的序列号和确认号(Ack)设置为客户端的初始序列号加1,并将它们发送回客户端。这个报文段的目的是告诉客户端,服务器已接收到连接请求,并同意建立连接。 - 第三次握手(ACK):
客户端接收到服务器的确认后,将确认号设置为服务器的初始序列号加1,并将ACK标志位设置为1,并发送回服务器。这个报文段的目的是告诉服务器,客户端已收到服务器的确认,连接已建立。
9、vue的钩子函数
Vue.js 是一个流行的前端框架,提供了一系列的钩子函数,用于在组件生命周期中执行特定的操作。以下是 Vue.js 中常见的钩子函数:
- beforeCreate: 在实例被创建之初,完成数据观测和初始化事件之前被调用。
- created: 在实例创建完成后被立即调用。此时实例已经完成数据观测,属性和方法的运算,以及对初始模板的编译等。
- beforeMount: 在挂载开始之前被调用。相关的 render 函数首次被调用。
- mounted: 实例被挂载后调用,此时 DOM 已经渲染完成,可以执行 DOM 操作。
- beforeUpdate: 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。可以在该钩子中进一步地更改数据,但要避免无限循环的更新。
- updated: 虚拟 DOM 重新渲染和打补丁之后调用。组件 DOM 已经更新,可以执行需要依赖于 DOM 的操作。
- beforeDestroy: 实例销毁之前调用。在这一步,实例仍然完全可用。
- destroyed: 实例销毁后调用。此时组件已经被移除,事件监听器被移除,所有的子实例也被销毁。
除了上述常见的钩子函数外,Vue.js 还提供了一些高级的钩子函数用于处理特定场景的操作,如异步组件的加载、动态组件的处理等。
这些钩子函数可以用于在组件生命周期不同阶段执行一些初始化、异步操作、DOM 操作等等,以满足不同的业务需求。开发者可以通过定义这些钩子函数中的相应方法来实现特定的逻辑。
10、Cookie、Session、Token相同点与区别详情
Cookie、Session和Token在Web应用程序中都用于身份验证和会话管理,但它们有相似之处,也有不同之处。以下是它们的相同点和区别的详细解释:
相同点:
-
-
-
- 身份验证:Cookie、Session和Token都可以用于对用户进行身份验证,确认用户的身份。
- 会话管理:Cookie、Session和Token都用于管理用户的会话状态,跟踪用户的活动和存储会话数据。
- 跨请求传递数据:Cookie、Session和Token都可以在客户端和服务器之间传递数据,用于存储和共享数据。
-
-
区别:
-
-
-
- 存储位置:
-
-
-
-
-
-
- Cookie:Cookie是存储在客户端(通常为浏览器)的小型文本文件。
- Session:Session数据存储在服务器端,一般保存在服务器的内存或数据库中。
- Token:Token是存储在客户端(通常为浏览器的存储区,如localStorage或sessionStorage)。
-
-
-
-
-
-
- 数据存储:
-
-
-
-
-
-
- Cookie:Cookie可以存储少量的文本数据(通常为字符串格式)。
- Session:Session可以存储较大的数据,并在服务器端维护会话状态。
- Token:Token通常包含用户的身份信息和其他相关数据,可以自由定义其内容和结构。
-
-
-
-
-
-
- 状态管理:
-
-
-
-
-
-
- Cookie:Cookie可以是持久性的,可以设置过期时间,也可以是会话性的,关闭浏览器后自动删除。
- Session:Session可以设置过期时间,当用户长时间不活动时,会话可能会失效。
- Token:Token可以设置过期时间,客户端可以在Token过期前更新Token。
-
-
-
-
-
-
- 安全性:
-
-
-
-
-
-
- Cookie:Cookie数据存储在客户端,可能会受到XSS(Cross-Site Scripting)和CSRF(Cross-Site Request Forgery)等安全漏洞的攻击。
- Session:Session数据存储在服务器端,相对更安全,但仍然可能受到Session劫持的攻击。
- Token:Token相对较安全,通过在客户端存储身份信息,减少了服务器端的存储需求。
-
-
-
-
-
-
- 扩展性:
-
-
-
-
-
-
- Cookie:Cookie由浏览器自动管理,适用于Web和移动端应用程序。
- Session:Session适用于服务器端应用程序,可以通过存储在数据库中实现跨服务器的会话共享。
- Token:Token适用于前后端分离的应用程序和API身份验证。
-
-
-
尽管Cookie、Session和Token都可以用于身份验证和会话管理,但具体的选择取决于应用程序的需求、安全性要求和现有的技术架构。
希望以上解释对您有所帮助!如果您还有其他问题,请随时提问。
四、数据库
1. 什么是MyBatis?
MyBatis 是一款开源的持久层框架,它提供了对关系型数据库的操作和访问的简化和优化。它通过将 Java 对象与 SQL 语句进行映射,使开发者可以以面向对象的方式进行数据访问,而无需编写繁琐的 JDBC(Java 数据库连接)代码。
MyBatis 的主要特点包括:
- 简化 SQL 编写:MyBatis 提供了一套强大而灵活的 XML 配置语言,可以将 SQL 语句与 Java 方法进行映射。这样,开发者只需要在 XML 配置文件中定义 SQL 语句,就能够通过调用对应的方法来执行这些 SQL 语句,从而避免了手动拼接 SQL 字符串的繁琐工作。
- 易于整合:MyBatis 可以与各种主流的 Java 框架(如 Spring、Spring Boot、Spring MVC)无缝集成。它提供了与这些框架的集成模块和插件,使得在项目中使用 MyBatis 变得非常简单。
- 提供灵活的映射配置:MyBatis 具有灵活的映射配置功能,可以将查询结果自动映射到指定的 Java 对象中。开发者可以通过配置映射规则,实现数据库记录与 Java 对象之间的转换,从而简化了数据操作的过程。
- 支持动态 SQL:MyBatis 提供了一套动态 SQL 语言,可以根据不同的条件拼接出不同的 SQL 语句。这使得在编写复杂查询时更加灵活和便利。
- 缓存功能:MyBatis 内置了一级缓存和二级缓存的支持,可以减少对数据库的频繁访问,提升性能。
总结来说,MyBatis 是一款轻量级、简单易用的持久层框架,通过简化 SQL 编写、灵活的映射配置、动态 SQL 和缓存功能等特点,使得开发者可以更高效地进行数据库访问,并且与各种 Java 框架无缝集成,广泛应用于各种规模的 Java 项目中。
2. MyBatis中#{}和${}的区别是什么?
在 MyBatis 中,#{} 和 ${} 是两种常用的 SQL 参数占位符形式,它们有一些区别。
- #{}:被 #{} 包裹的占位符会被 MyBatis 解析成预编译语句中的参数占位符(PreparedStatement),这样可以有效防止 SQL 注入攻击。在使用 #{} 时,MyBatis 会自动为传入的参数添加转义字符,例如将字符串类型的参数 'abc' 转义为 'abc',从而确保参数值的安全性。因此,使用 #{} 更加安全可靠。
- ${}:被 ${} 包裹的占位符会直接替换成实际的参数值,在生成 SQL 语句时起到字符串替换的作用,类似于字符串拼接的效果。但是,由于 ${} 不提供参数转义的机制,使用 ${} 存在潜在的 SQL 注入风险。因此,如果不可信任的数据直接拼接到 SQL 语句中,可能导致安全问题。
总结来说,#{} 是较为安全的参数占位符形式,在进行 SQL 拼接时会对参数进行转义处理,能有效预防 SQL 注入。而 ${} 则是简单的字符串替换形式,适用于某些特定需求,但需要谨慎使用以避免安全风险。在实际使用中,建议优先使用 #{} 来保证 SQL 的安全性。
3.数据库中视图是什么?
据库中的视图(View)是一种虚拟表,它基于一个或多个数据库表的查询结果而创建。视图并不实际存储数据,而是根据定义的查询逻辑在查询时动态生成结果。
视图可以理解为从一个或多个表中选取特定的列和行,形成一个新的逻辑表格。通过创建视图,可以将复杂的查询逻辑封装起来,并提供了简化和便利的数据访问方式。
主要特点和作用:
- 数据抽象:视图隐藏了底层表的细节,对用户来说,只需要关注视图的结构和内容即可,无需关心数据存储和查询的具体细节。
- 简化查询操作:通过创建视图,可以预先定义好常用的查询,避免反复编写复杂的 SQL 查询语句,提升查询的简洁性和效率。
- 数据安全:通过视图,可以限制用户对数据的访问权限,只暴露指定的列或行给用户,提升了数据的安全性和隐私保护。
- 逻辑重组:视图可以对底层表进行逻辑上的重新组织和聚合,使得数据模型更符合业务需求,提供更便捷的数据操作接口。
- 简化复杂计算逻辑:通过在视图中应用聚合函数、计算列等操作,可以在查询时直接得到所需的计算结果,避免了手动进行复杂的计算过程。
需要注意的是,视图本身并不存储实际的数据,其查询结果会随着底层表数据的变化而动态更新。另外,视图可以与表一样被查询、更新和删除,但对视图的修改操作通常会反映到底层表上。
总结来说,数据库中的视图是基于一个或多个表查询结果的虚拟表格,它提供了数据抽象、简化查询操作、数据安全、逻辑重组和简化复杂计算逻辑等功能,为用户提供便捷
4.三大范式
三大范式(Normalization)是数据库设计中的规范,旨在提高数据模型的可理解性、灵活性和数据完整性。以下是三大范式的简要描述:
- 第一范式(1NF):确保数据库表中的每个列都包含原子性的值,不允许多个值或重复值存在于同一列中。此范式消除了重复数据,并使每个数据项具有唯一性。
- 第二范式(2NF):在1NF的基础上,要求非主键列完全依赖于表的候选键(即实体的唯一标识)。换句话说,每个非主键列必须完全依赖于表的主键,而不能依赖于部分主键。通过使用分解(拆分)表来消除冗余数据,以确保关联数据之间的一致性。
- 第三范式(3NF):在2NF的基础上进一步规范化,要求非主键列之间没有传递依赖关系。换句话说,非主键列之间不应该相互依赖。通过进一步分解表,将非主键列移至与其恰好相关的独立表中,以消除传递依赖关系。
通过遵循这些范式,数据库设计可以减少数据冗余、提高数据的一致性和准确性,并简化数据操作和维护。然而,在某些情况下,过度规范化可能会导致性能问题,需要根据实际需求进行权衡和调整。
5、事务的ACID 是指什么?
事务的ACID是指数据库管理系统中事务应具备的四个特性,分别是原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
- 原子性(Atomicity):事务是一个不可分割的工作单位,要么全部执行成功,要么全部不执行。如果事务中的任何一个操作失败,则整个事务都会被回滚到初始状态,保证数据的一致性。
- 一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏。事务执行的结果必须使数据库从一个一致状态变到另一个一致状态,即事务对数据库的修改必须符合预定的规则,保证数据的有效性和合法性。
- 隔离性(Isolation):事务的并发执行是相互隔离的,每个事务在读取和修改数据时,都好像是在独立运行,互不干扰。隔离性可以防止在并发环境下出现脏读、不可重复读、幻读等问题,保证事务的独立性和数据的准确性。
- 持久性(Durability):一旦事务提交,其对数据库的修改就是永久性的,即使系统发生故障也不会丢失。持久性保证了事务的结果能够被持久地保存在数据库中,即使在系统故障或断电等情况下,也能够恢复数据的一致性。
ACID特性确保了事务的可靠性和数据的完整性,使得数据库管理系统能够提供可靠的数据处理和并发控制机制。
6、mysql中innerjoin 和 leftjoin 有什么区别?
在 MySQL 中,INNER JOIN 和 LEFT JOIN 是用于连接多个表的操作,它们之间的主要区别如下:
- INNER JOIN(内连接):
-
- INNER JOIN 会根据连接条件从两个表中匹配符合条件的行,并将匹配的结果返回。
- 只返回匹配的行,即两个表中都存在匹配的数据才会返回,不论是单个匹配还是多个匹配。
- 如果一个表中的某行没有与另一个表中的任何行匹配,则该行将被忽略。
- LEFT JOIN(左连接):
-
- LEFT JOIN 会返回左表的所有行,以及与左表中的行匹配的右表的行。
- 即使右表中没有与左表中的行匹配的数据,仍然会返回左表中的行,右表中对应位置的数据为空。
- 如果右表的某行没有与左表的任何行匹配,则返回的结果中该行的右表数据为 NULL。
简而言之,INNER JOIN 只返回两个表之间匹配的行,而 LEFT JOIN 则返回左表的所有行和与其匹配的右表行,如果没有匹配的右表行,则返回 NULL。
3、union 外连接
7、mysql的索引有哪几种?索引有什么作用及优缺点?
在 MySQL 中,常见的索引类型主要包括以下几种:
- B树索引:
-
- B树索引是最常见的索引类型,适用于查询条件为范围查询(<、>、<=、>=)的情况。
- B树索引按照索引列的值进行排序,并将数据存储在一个平衡的B树结构中,可以快速定位到满足查询条件的数据。
- 适用于等值查询和范围查询,不适用于全文搜索和模糊查询。
- 哈希索引:
-
- 哈希索引是基于哈希算法实现的索引,将索引列的值映射成哈希值,通过哈希值快速定位到数据所在的位置。
- 适用于等值查询,对于范围查询和排序操作效果较差。
- 哈希索引不支持部分索引列查询和索引列排序,只能应用于精确匹配,对于重复值较多的索引列可能会有哈希冲突。
- 全文索引:
-
- 全文索引用于实现全文搜索,在文本数据上进行关键字的查找和匹配。
- 适用于模糊查询和全文搜索的场景,如文章内容搜索、博客文章标签等。
- 全文索引的查询效率较高,但会占用较大的磁盘空间,并且维护全文索引需要一定的时间和资源。
索引的作用和优缺点如下:
作用:
-
- 提高数据查询的速度:通过使用索引,可以快速定位到满足查询条件的数据,减少了数据库的扫描次数,提高了查询效率。
- 加速排序操作:对于排序操作,索引可以以特定的顺序存储数据,加快排序的速度。
- 保证数据的唯一性:索引可以定义为唯一索引,用于确保索引列中的值是唯一的。
优点:
-
- 提高查询速度和性能:索引可以快速定位到符合条件的数据行,减少全表扫描的开销,提高查询速度和性能。
- 加速排序和分组操作:索引有助于加速排序和分组等操作,提高相关SQL语句的执行效率。
- 保证数据完整性和一致性:唯一索引可以确保索引列中的值是唯一的,避免重复数据的插入。
缺点:
-
- 占用额外的存储空间:索引需要占用额外的存储空间,特别是对于大型表和多个索引的表来说,索引可能会占据相当大的空间。
- 增删改操作的性能下降:索引需要在每次增删改数据时进行维护,对于频繁进行数据更新的表,索引的维护可能会带来一定的
8、redis的数据类型有哪些?常用的业务场景有哪些?
Redis支持的常用数据类型包括:
- 字符串(String):存储字符串、整数或二进制数据。
- 哈希表(Hash):存储字段和值的映射关系。
- 列表(List):按照插入顺序存储多个字符串。
- 集合(Set):无序且唯一的字符串集合。
- 有序集合(Sorted Set):类似于集合,但每个成员都关联一个分数,用于排序。
常用的业务场景包括:
- 缓存:使用Redis作为缓存数据的存储,加快数据访问速度,减轻后端数据库的负载压力。
- 计数器:通过Redis的原子操作实现计数功能,例如网站的访问量、点赞数等。
- 消息队列:利用Redis的列表数据结构实现简单的消息队列,用于解耦系统组件之间的通信。
- 分布式锁:利用Redis提供的原子操作和过期时间特性,实现分布式环境中的互斥操作。
- 实时排行榜:使用有序集合存储成员和对应的分数,根据分数排序获取排行榜信息。
- 发布/订阅:利用Redis的发布/订阅功能,实现消息的广播和订阅者的实时接收。
这些只是Redis的一些常见用途,它还可以根据具体业务需求进行灵活的应用和扩展。
9.Mybatis 相较于 jdbc 区别
MyBatis是一种持久化框架,而JDBC是Java数据库连接的标准接口。它们之间有以下区别:
- 编程模型:使用JDBC时,需要手动编写大量的连接管理、SQL语句拼装、结果集处理等代码。而MyBatis通过提供基于XML或注解的配置方式,封装了这些细节,使开发者只需关注SQL语句和映射关系。
- SQL控制:在JDBC中,SQL语句的控制权完全交给开发者,包括参数传递、结果集映射等。而MyBatis通过动态SQL的机制,可以根据条件灵活组装SQL语句,简化参数处理和结果集映射。
- 参数与结果集映射:JDBC中,开发者需要手动设置参数并处理结果集的映射,其操作较为繁琐。而MyBatis通过配置文件或注解,提供了方便的参数传递和结果集映射功能,可以将结果映射到Java对象上。
- 数据库事务:使用JDBC时,需要手动管理事务,如设置连接的自动提交、回滚等。而MyBatis支持声明式的事务管理,可以通过配置和注解来控制事务的边界和隔离级别,简化了事务管理的工作。
- 缓存机制:MyBatis内置了缓存机制,默认开启二级缓存,可以提升查询性能。而JDBC没有缓存机制,每次查询都需要与数据库进行交互。
总而言之,MyBatis相较于JDBC在开发效率、SQL控制、参数与结果集映射以及事务管理等方面提供了更高的抽象和便利性,使开发者能够更加专注于业务逻辑的实现。
10.Char与varchar区别
1、最大长度:
char最大长度是255字符,varchar最大长度是65535个字节。
2、定长:
char是定长的,不足的部分用隐藏空格填充,varchar是不定长的。
3、空间使用:
char会浪费空间,varchar会更加节省空间。
4、查找效率:
char查找效率会很高,varchar查找效率会更低。
5、尾部空格:
char插入时可省略,vaechar插入时不会省略,查找时省略。
11、MyBatis中可用的几种动态SQL元素
- if 元素:
if元素用于根据条件判断是否包含某个SQL片段。例如:
<select id="getUserList" resultType="User">
SELECT * FROM user
WHERE 1=1
<if test="name != null">
AND name = #{name}
</if>
<if test="age != null">
AND age = #{age}
</if>
</select>
上述示例中,如果name参数不为null,则会在SQL中包含AND name = #{name}的条件。
- choose, when, otherwise 元素:
choose元素类似于Java中的switch语句,用于在一组条件中选择一个。when元素用于定义每个条件,otherwise元素用于定义默认条件。例如:
<select id="getUserList" resultType="User">
SELECT * FROM user
WHERE 1=1
<choose>
<when test="name != null">
AND name = #{name}
</when>
<when test="age != null">
AND age = #{age}
</when>
<otherwise>
AND active = true
</otherwise>
</choose>
</select>
上述示例中,如果name和age参数都为null,则会使用默认的条件AND active = true。
- trim, where, set 元素:
trim元素可用于动态地去除生成的SQL语句中的多余空白字符,并在指定条件下添加额外的SQL片段。where元素用于在生成的SQL中添加WHERE子句,set元素用于生成UPDATE语句中的SET子句。例如:
<update id="updateUser" parameterType="User">
UPDATE user
<set>
<if test="name != null">
name = #{name},
</if>
<if test="age != null">
age = #{age},
</if>
</set>
WHERE id = #{id}
</update>
12、sql优化
- 优化查询语句:
-
- 确保使用合适的索引,索引能够有效地加快查询速度。
- 避免使用通配符开头的模糊查询,这会导致全表扫描。
- 尽量减少子查询和嵌套查询的使用,可以考虑使用联接(JOIN)来替代。
- 注意使用合适的WHERE条件,尽量避免对大量数据进行无效的操作。
- 避免使用SELECT *,只选择需要的列,减少网络传输的开销。
- 优化数据库结构:
-
- 合理设计数据库的表结构,避免冗余和重复的数据存储。
- 使用合适的数据类型和大小,避免浪费存储和计算资源。
- 通过规范化和反规范化来优化表关系,提高查询性能。
- 考虑分区和分片等技术,将数据划分为更小的单元进行处理。
- 缓存技术:
-
- 使用缓存来减少数据库查询的次数,例如使用Redis或Memcached。
- 对于频繁查询的数据,可以将结果缓存到应用程序中,避免每次都查询数据库。
- 执行计划分析:
-
- 使用数据库的查询分析工具,如EXPLAIN或SQL Profiler,分析查询的执行计划,找出问题所在。
- 根据执行计划的结果,优化查询语句或数据库结构,提高查询性能。
- 控制并发:
-
- 合理设计数据库的并发控制策略,避免数据竞争和死锁。
- 适当使用事务,减少事务的范围和锁的持有时间。
- 定期维护:
-
- 定期清理无用数据和索引,优化数据库的空间和性能。
- 更新数据库统计信息,以便优化查询优化器的查询计划。
13、如何避免索引失效
- 确保正确选择和创建索引:
-
- 根据查询的实际需求选择适当的索引,考虑查询的字段、表的大小和查询频率等因素。
- 使用复合索引来覆盖多个查询条件,避免不必要的索引扫描。
- 避免创建过多的索引,因为索引的维护和更新也会有开销。
- 避免索引列上的函数处理:
-
- 当在索引列上使用函数时,数据库无法使用索引,而是对所有的数据进行函数处理。
- 尽量避免在索引列上使用函数,可以通过应用程序处理或者使用存储过程等方式来处理数据。
- 避免模糊查询的开头使用通配符:
-
- 当模糊查询的开头使用通配符(例如LIKE ‘%keyword’),数据库无法使用索引进行快速匹配。
- 尽量避免在查询的开头使用通配符,可以考虑使用全文搜索或其他技术来改进模糊查询的性能。
- 注意查询语句的书写顺序:
-
- 将查询条件中经常出现的字段放在前面,这有助于数据库快速筛选出结果。
- 在使用OR条件时,将开销较小的条件放在前面,以提高查询效率。
- 定期更新统计信息:
-
- 统计信息帮助数据库优化器选择合适的查询计划,因此需要定期更新统计信息。
- 使用数据库提供的命令或脚本来更新统计信息,以确保查询优化器可以做出正确的决策。
- 定期进行索引维护:
-
- 当数据量发生较大变动、删除操作频繁或数据分布不均匀时,索引的效果可能会受到影响。
- 定期进行索引重建或碎片整理等维护操作,以保持索引的效率和稳定性。
14、Redis
Redis是一个开源的、基于内存的数据结构存储系统,通常被用作缓存、消息代理和数据存储。它支持多种数据结构,如字符串、哈希、列表、集合和有序集合,并提供了丰富的操作命令。Redis的主要特点包括
- 内存存储:Redis的数据存储在内存中,读写速度非常快。同时,它也支持将数据异步持久化到磁盘上,以防止数据丢失。
- 数据类型的灵活性:Redis支持多种数据类型,并且每种数据类型都有对应的操作命令,使得开发者能够根据需要执行各种复杂的操作。
- 高可用性:Redis支持主从复制、哨兵和集群等机制,以确保系统的高可用性和容错性。
- 发布订阅模式:Redis可以作为消息代理,支持发布订阅模式,让开发者能够实现消息传递和实时通信。
- 扩展性:Redis可以通过添加多个节点来扩展性能和存储容量,从而应对高并发和大规模数据的需求。
总的来说,Redis是一个强大的、多功能的数据存储系统,广泛应用于互联网应用、缓存系统、实时数据处理和消息队列等场景。
redis数据类型
- 字符串(String):字符串是最简单的数据类型,可以存储文本、数字或二进制数据。Redis对字符串提供了丰富的操作命令,如设置值、获取值、追加数据、计数器操作等。
- 哈希(Hash):哈希是一个键值对的集合,适合存储对象。在Redis中,可以使用哈希类型来存储和获取对象的字段和相关值。
- 列表(List):列表是一个有序的字符串集合,可以在列表的两端进行插入和删除操作。列表适用于存储需要保持顺序的数据,比如消息队列、最近浏览记录等。
- 集合(Set):集合是一个无序的字符串集合,每个集合中的元素都是唯一的。集合支持添加、删除、查找、交集、并集等操作,适合处理无需保持顺序且需要唯一性的数据。
- 有序集合(Sorted Set):有序集合是一个有序的字符串集合,每个元素都会关联一个分数,用于排序。有序集合支持添加、删除、查找、按照分数范围获取元素等操作,适用于排行榜、计分系统等场景。
除了上述主要的数据类型,Redis还支持其他数据类型,如位图(Bitmap)、超日志(HyperLogLog)和地理位置(GeoSpatial)等,每种数据类型都有其特有的功能和优势。开发者可以根据实际需求选择合适的数据类型来存储和处理数据。
15、事务隔离级别
常见的事务隔离级别:
- 读未提交(Read Uncommitted):最低级别,事务可以读取未提交的数据,可能会导致脏读(Dirty Read)问题。
- 读已提交(Read Committed):保证一个事务读取到的数据是已经提交的数据,解决了脏读问题,但可能出现不可重复读(Non-repeatable Read)问题。
- 可重复读(Repeatable Read):保证在一个事务中多次读取同一数据时,其值不会改变,解决了不可重复读问题,但可能出现幻读(Phantom Read)问题。
- 串行化(Serializable):最高级别,通过对事务进行串行执行,避免了脏读、不可重复读和幻读问题,但会影响并发性能。
需要注意的是,隔离级别越高,事务的并发性能越低,因为隔离级别的提升会引入额外的锁机制和数据一致性检查。通常情况下,默认的隔离级别是数据库自身设置的,可以在需要的时候通过设置来修改事务隔离级别。
16、数据库连接池
数据库连接池是一种用于管理和复用数据库连接的技术,它能够提高数据库访问的性能和资源利用率。数据库连接池中维护着一组数据库连接,应用程序可以从连接池中获取连接,并在使用完后将连接返回给连接池,以便其他请求继续使用。
使用数据库连接池的好处包括:
- 连接复用和管理:数据库连接池可以避免频繁创建和销毁数据库连接的开销,提高连接的复用和管理效率。连接池可以预先创建一定数量的连接,在需要时分配给应用程序,使用完后再将连接放回连接池,以供其他请求使用。
- 提高性能:连接池中的连接已经初始化并与数据库建立了连接,因此可以减少连接的创建时间和认证过程,从而提高数据库访问的性能。
- 连接资源的控制:连接池可以限制同时访问数据库的连接数,防止连接数过多导致数据库性能下降或崩溃。通过设置最大连接数和最小空闲连接数等参数,可以对连接的数量进行控制。
- 连接的可用性和容错处理:连接池可以对连接进行监控,及时检测连接的可用性,如果连接失效或发生异常,可以自动从连接池中移除并创建新的连接,确保连接的可用性和系统的稳定性。
常见的数据库连接池包括如下几种:
- Apache Commons DBCP (Dbcp2): Apache Commons DBCP 是 Apache 提供的一个常用的开源数据库连接池库,具有较好的性能和稳定性。
1. Apache Commons DBCP(数据库连接池)是 Apache Software Foundation 提供的一个开源数据库连接池实现,它是 Apache Commons 的一部分。下面对 Apache Commons DBCP 进行详细解释:
-
-
- 特性和优势:
-
-
-
-
- 高性能:Apache Commons DBCP 提供了一种高性能的连接池实现,它可以管理和复用数据库连接,减少了连接的创建和销毁开销,提高了数据库访问的性能。
- 稳定性和可靠性:Apache Commons DBCP 经过长期的发展和验证,在生产环境中被广泛使用,具有稳定性和可靠性。
- 灵活的配置选项:Apache Commons DBCP 提供了丰富的配置选项,可以根据具体的应用需求进行灵活的配置,如最大连接数、最大空闲连接数、连接超时等。
- 连接池监控和管理:Apache Commons DBCP 具有连接池的监控和管理功能,可以实时监控连接的状态和可用性,确保连接池的稳定运行。
-
-
-
-
- 工作原理:
-
-
-
-
- 连接池参数:可以配置连接池的最大连接数(maxPoolSize)、最大空闲连接数setMaxIdleTime、最小空闲连接数(minPoolSize)、连接超时时间(checkoutTimeout)等参数。
- 连接获取和释放:应用程序通过获取连接池管理的连接对象来执行数据库操作,当操作完成后,将连接返回给连接池进行复用。
- 连接池管理:Apache Commons DBCP 负责管理连接的创建、销毁和复用,它会根据连接池的配置和应用程序的需求来动态调整连接的数量。
- 连接池监控:Apache Commons DBCP 提供了连接池的监控功能,可以通过 JMX 或 API 获取连接池的状态信息,如活动连接数、空闲连接数、等待的请求数等。
-
-
-
-
- 配置选项:
-
-
-
-
- 连接池参数:可以配置连接池的最大连接数、最大空闲连接数、最小空闲连接数、连接超时时间等参数。
- 连接验证:可以定义验证 SQL 查询语句,连接池会定期执行该查询,以确保连接的有效性。
- 连接池监控:可以开启连接池的监控功能,监控连接池的状态和性能指标,并可以集成到系统的监控工具中。
-
-
-
-
- 使用示例:
下面是一个简单的使用 Apache Commons DBCP 的示例:
- 使用示例:
-
import org.apache.commons.dbcp2.BasicDataSource;
public class Main {
public static void main(String[] args) {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:mysql://localhost:3306/mydatabase");
dataSource.setUsername("username");
dataSource.setPassword("password");
// 获取数据库连接
try (Connection conn = dataSource.getConnection()) {
// 执行数据库操作
} catch (SQLException e) {
e.printStackTrace();
}
}
}
以上示例中,我们创建了一个 BasicDataSource 对象来配置数据库连接池的相关属性,然后通过 getConnection()
方法获取数据库连接。
总而言之,Apache Commons DBCP 是一个成熟和可靠的数据库连接池实现,通过合理配置和使用,可以提高数据库访问的性能和效率。在使用过程中,建议参考官方文档和 API 文档,根据具体需求进行配置和优化。
- HikariCP:HikariCP 是一个轻量级且高性能的数据库连接池,被广泛认为是性能最好的数据库连接池。
- C3P0:C3P0 是一个成熟的开源数据库连接池,它提供了灵活的配置选项和连接池管理功能。
2. C3P0 是一个开源的 JDBC 数据库连接池实现,它提供了高性能、稳定可靠的连接池功能,用于管理和复用数据库连接。下面对 C3P0 进行详解:
-
-
- 特性和优势:
-
-
-
-
- 高性能:C3P0 基于高性能的连接池实现,能够管理和复用数据库连接,减少了连接的创建和销毁开销,提高了数据库访问的性能。
- 可靠性和稳定性:C3P0 经过长期发展和广泛验证,具有可靠性和稳定性,在生产环境中被广泛使用。
- 灵活的配置选项:C3P0 提供了丰富的配置选项,可以根据具体的应用需求进行灵活的配置,如最大连接数、最大空闲连接数、连接超时等。
- 连接池监控和管理:C3P0 提供了连接池的监控和管理功能,可以监控连接的状态和可用性,确保连接池的稳定运行。
-
-
-
-
- 工作原理:
-
-
-
-
- 连接池初始化:在应用程序启动时,可以通过配置文件或编程方式初始化连接池,设置连接池的属性,如连接数、初始连接数、连接超时等。
- 连接获取和释放:应用程序通过获取连接池管理的连接对象来执行数据库操作,当操作完成后,将连接返回给连接池,以便其他请求继续使用。
- 连接池管理:C3P0 负责管理连接的创建、销毁和复用,它会根据连接池的配置和应用程序的需求来动态调整连接的数量。
- 连接池监控:C3P0 提供了连接池的监控功能,可以通过 JMX 或 API 获取连接池的状态信息,如活动连接数、空闲连接数、等待的请求数等。
-
-
-
-
- 配置选项:
-
-
-
-
- 连接池参数:可以配置连接池的最大连接数(maxPoolSize)、最大空闲连接数setMaxIdleTime、最小空闲连接数(minPoolSize)、连接超时时间(checkoutTimeout)等参数。
- 连接验证:可以定义验证 SQL 查询语句,C3P0 会定期执行该查询,以确保连接的有效性。
- 连接池监控:可以开启连接池的监控功能,监控连接池的状态和性能指标,并可以集成到系统的监控工具中。
-
-
-
-
- 使用示例:
下面是一个简单的使用 C3P0 的示例:
- 使用示例:
-
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class Main {
public static void main(String[] args) {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mydatabase");
dataSource.setUser("username");
dataSource.setPassword("password");
// 获取数据库连接
try (Connection conn = dataSource.getConnection()) {
// 执行数据库操作
} catch (SQLException e) {
e.printStackTrace();
}
}
}
以上示例中,我们创建了一个 ComboPooledDataSource 对象来配置数据库连接池的相关属性,然后通过 getConnection()
方法获取数据库连接。
总而言之,C3P0 是一个成熟和可靠的数据库连接池实现,通过合理配置和使用,可以提高数据库访问的性能和效率。在使用过程中,建议参考官方文档和 API 文档,根据具体需求进行配置和优化。
- BoneCP:BoneCP 是另一个快速且轻量级的数据库连接池,具有高并发性能和可靠性。
这些数据库连接池都提供了丰富的配置选项,可以根据需求进行调整和优化。通过使用这些连接池,可以简化数据库连接的管理和提高数据库访问的性能和效率。在使用连接池时,需要根据具体情况选择合适的连接池实现,并进行合理的配置和使用。
17、union unionall
"UNION" 和 "UNION ALL" 用于在 SQL 查询中合并多个结果集。这两个操作符有以下区别
- UNION:
-
- UNION 运算符用于合并两个或多个 SELECT 语句的结果集,并去除重复的行。如果存在相同的行,则只保留一份。
- UNION 要求被合并的 SELECT 语句的列数和列类型必须一致。
- UNION 默认按照 SELECT 语句的顺序对结果进行排序。
例如:
SELECT column1, column2 FROM table1
UNION
SELECT column1, column2 FROM table2;
- UNION ALL:
-
- UNION ALL 运算符也用于合并两个或多个 SELECT 语句的结果集,但不去除重复的行。结果集中可能包含重复的行。
- UNION ALL 不对结果进行排序,返回的结果集按照 SELECT 语句的顺序组合。
例如:
SELECT column1, column2 FROM table1
UNION ALL
SELECT column1, column2 FROM table2;
使用 UNION 和 UNION ALL 可以在查询中将多个结果集组合在一起。通常情况下,如果你需要合并多个结果集并去除重复的行,则使用 UNION 操作符;如果你希望保留所有的行,包括重复的行,则使用 UNION ALL 操作符。
需要注意的是,UNION 和 UNION ALL 操作符适用于查询相互兼容的结果集,即列数和数据类型必须匹配。此外,它们也可以用于从不同的表或视图中获取数据进行联合查询。
18、sql去重的方式
在 SQL 中,有几种方式可以实现去重操作,具体取决于你使用的数据库管理系统。下面介绍几种常见的去重方式:
- 使用 DISTINCT 关键字:
可以使用 SELECT 语句的 DISTINCT 关键字来去除结果集中的重复行。DISTINCT 会对查询结果的所有列进行比较,并只返回不重复的行。
例如:
SELECT DISTINCT column1, column2 FROM table;
- 使用 GROUP BY:
可以使用 GROUP BY 子句对查询结果进行分组,并使用聚合函数(如 COUNT、SUM)对每个分组进行计算。在这种情况下,重复的行会被分组并合并成一个结果行。
例如:
SELECT column1, column2 FROM table GROUP BY column1, column2;
- 使用窗口函数(Window Functions):
某些数据库管理系统支持窗口函数,如 ROW_NUMBER()、RANK()、DENSE_RANK() 等,可以对查询结果进行排序和编号。通过结合 PARTITION BY 子句,可以为每个分组内的行赋予一个唯一的编号,然后根据编号进行筛选。
例如:
SELECT column1, column2
FROM (
SELECT column1, column2, ROW_NUMBER() OVER (PARTITION BY column1, column2 ORDER BY column1) as row_num
FROM table
) t
WHERE row_num = 1;
- 使用子查询:
在多个子查询中使用 UNION 或 UNION ALL 时,可以利用子查询的结果进行去重操作。将原始查询结果作为子查询,然后在外部查询中使用 DISTINCT 关键字去除重复行。
例如:
SELECT DISTINCT column1, column2
FROM (
SELECT column1, column2 FROM table1
UNION ALL
SELECT column1, column2 FROM table2
) subquery;
根据具体的需求和数据库管理系统的支持,你可以选择适合的方法来实现去重操作。同时,确保查询语句中使用的列名和数据类型是一致的,以确保正确的去重结果。
五、linux
1、端口
Http/Nginx 80
SVN 3690
RabbitMQ 5672
Redis 6379
Tomcat/Jboss 8080
Nacos(注册中心)8848
Elasticsearch 9200
21 FTP(文件传输)
22 SSH(安全登录)、SCP(文件传输)、端口重定向
23 Telnet(远程登录)
80 HTTP服务器
1433 SQL Server数据库server
1434 SQLServer数据库monitor
1521 Oracle 数据库
1158 ORACLE EMCTL
2100 Oracle XDB FTP服务
2181 ZooKeeper
3306 MySQL
5672 RabbitMQ
6379 redis
7001 WebLogic
8080 TOMCAT、JBOSS、Oracle XDB( XML 数据库)
8161/61616 ActiveMQ
8761 Eureka
8983 solr
9080 Webshpere应用程序
9090 webshpere管理工具
9092 kafka
9200 ElasticSearch
20880 dubbo
26379 redis哨兵
27017 MongoDB
2、Nginx中,实现反向代理可以通过配置Nginx的代理模块来完成
- 安装和配置Nginx:首先,确保已经安装了Nginx服务器,并正确配置好主机和端口。
- 打开Nginx配置文件:默认情况下,Nginx的配置文件位于/etc/nginx/nginx.conf。使用文本编辑器打开该文件。
- 配置反向代理:在配置文件中找到或创建一个名为server的代码块,该代码块定义了一个虚拟主机。在该代码块内,添加以下配置语句来实现反向代理:
其中,/表示匹配所有请求路径,http://backend_server是实际提供服务的后端服务器的地址。
- 配置后端服务器:在配置文件中找到或创建一个名为http的代码块,在其中定义一个名为upstream的块。在这个upstream块里,通过添加以下语句来定义后端服务器的地址:
其中,backend_ip是后端服务器的IP地址,backend_port是后端服务器监听的端口号。
- 保存并退出配置文件。
- 重新加载Nginx配置:在命令行中执行以下命令,让Nginx重新加载配置文件
3、常用的Linux命令:
1. 文件和目录操作:
-
- ls:列出目录内容。
- cd:切换目录。
- pwd:显示当前所在目录的路径。
- mkdir:创建新目录。
- rm:删除文件或目录。
- mv:移动文件或目录。
- cp:复制文件或目录。
- touch:创建新文件或更新文件的时间戳。
- cat:显示文件内容。
2. 文件查找和过滤:
-
- find:按照指定的条件查找文件。
- grep:在文件中搜索匹配指定模式的文本。
- wc:计算文件的行数、单词数和字节数。
3. 系统信息:
-
- uname:显示系统信息。
- uptime:显示系统的运行时间和负载情况。
- df:显示文件系统的磁盘空间使用情况。
- free:显示系统内存的使用情况。
- top:实时显示系统中运行的进程信息。
4. 用户和权限管理:
-
- whoami:显示当前登录的用户名。
- passwd:修改用户密码。
- useradd:创建新用户。
- userdel:删除用户。
- chmod:修改文件或目录的权限。
- chown:修改文件或目录的所有者。
- chgrp:修改文件或目录的所属组。
5. 网络相关:
-
- ping:向网络主机发送ICMP Echo请求以测试连接性。
- ifconfig:显示和管理网络接口配置。
- ip:显示和管理网络接口、路由等网络配置。
- netstat:显示网络连接、路由表等信息。
- wget:从指定URL下载文件。