第一天
1.Java内部类有哪些,特征是什么?
成员内部类(Member Inner Class):定义在一个类的内部,并且与外部类的成员变量和方法具有相同的访问权限。成员内部类可以访问外部类的所有成员,包括私有成员。
局部内部类(Local Inner Class):定义在一个方法或代码块的内部,作用范围仅限于所在的方法或代码块。局部内部类可以访问外部类的成员,但只能访问final或有效final的局部变量。
静态内部类(Static Inner Class):定义在一个类的内部,并且被static修饰。静态内部类与外部类的实例无关,可以直接通过外部类的类名访问静态内部类的静态成员。静态内部类可以访问外部类的静态成员,但不能直接访问外部类的非静态成员。
匿名内部类(Anonymous Inner Class):没有显式的类名,直接通过new关键字创建。匿名内部类通常用于创建实现某个接口或继承某个类的对象,并重写其方法。匿名内部类可以访问外部类的成员,但只能访问final或有效final的局部变量。
特征:
内部类可以访问外部类的成员,包括私有成员。
内部类可以拥有自己的成员变量和方法。
内部类可以被private、protected、public和default修饰。
内部类可以访问外部类的this关键字,用于区分内部类和外部类的成员。
内部类可以用于实现多重继承,一个类可以实现多个接口,每个接口可以有自己的内部类实现。
内部类可以访问外部类的静态成员,但外部类不能直接访问内部类的成员,需要通过创建内部类的对象来访问。
2.数据库的垂直切分和水平切分两种 他们的区别是什么?
数据库的垂直切分(Vertical Partitioning)和水平切分(Horizontal Partitioning)是两种常用的数据库分片技术,它们的区别如下:
垂直切分:
垂直切分是将一个数据库表按照列的方式进行切分,将不同的列划分到不同的表中。
垂直切分可以将数据按照功能或者访问频率进行划分,将不同的列存储在不同的表中,从而提高查询性能和减少数据冗余。
垂直切分可以实现更好的数据隔离和安全性,因为不同的表可以设置不同的权限和访问控制。
垂直切分的缺点是可能会导致多表关联查询的复杂性增加,需要进行额外的表连接操作。
水平切分:
水平切分是将一个数据库表按照行的方式进行切分,将不同的行划分到不同的表或者不同的数据库中。
水平切分可以将数据按照某个字段的值进行划分,例如将用户按照地域或者按照用户ID的范围进行划分。
水平切分可以实现更好的负载均衡,因为不同的行可以存储在不同的表或者不同的数据库中,从而分散了查询和写入的压力。
水平切分的缺点是可能会导致跨节点查询的复杂性增加,需要进行额外的数据合并和查询操作。
总的来说,垂直切分适用于将不同的功能或者访问频率较低的列划分到不同的表中,而水平切分适用于将数据按照某个字段的值进行划分,实现负载均衡和分散压力。垂直切分和水平切分也可以结合使用,根据实际需求选择合适的切分策略。
3.手写一个冒泡排序
public class BubbleSort {
public static void bubbleSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// 交换arr[j]和arr[j+1]
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
public static void main(String[] args) {
int[] arr = {64, 34, 25, 12, 22, 11, 90};
bubbleSort(arr);
System.out.println("排序后的数组:");
for (int num : arr) {
System.out.print(num + " "); //11 12 22 25 34 64 90
}
}
}
4.谈谈你对HTTP协议的认识?
HTTP协议是一种用于传输超文本的应用层协议,它是Web的基础,是Web应用程序的基础。HTTP协议是客户端和服务器之间通信的标准协议,客户端发送请求,服务器返回响应。HTTP协议基于TCP/IP协议,通过TCP协议传输数据,使用URL作为定位网络资源的标识符,支持多种请求方法,如GET、POST、PUT、DELETE等,支持多种数据格式,如HTML、XML、JSON等。HTTP协议的主要特点是简单、灵活、可扩展、无状态。HTTP协议的简单性使得它易于实现和使用,灵活性和可扩展性使得它适用于各种不同的应用场景,无状态使得它可以处理大量的请求。HTTP协议的缺点是安全性较差,数据传输不加密,容易被攻击者截获和篡改。为了提高安全性,现在常用的是HTTPS协议,它在HTTP协议的基础上增加了SSL/TLS加密技术,保证数据传输的安全性。
5.谈谈你对TCP三次握手/四次挥手
CP三次握手是TCP协议在建立连接时的一种机制。它的过程如下:
- 客户端向服务器发送SYN包,表示请求建立连接。
- 服务器收到SYN包后,向客户端发送SYN+ACK包,表示确认收到请求并同意建立连接。
- 客户端收到SYN+ACK包后,向服务器发送ACK包,表示确认收到确认,并建立连接。
TCP四次挥手是TCP协议在断开连接时的一种机制。它的过程如下:
- 客户端向服务器发送FIN包,表示请求断开连接。
- 服务器收到FIN包后,向客户端发送ACK包,表示确认收到请求。
- 服务器向客户端发送FIN包,表示请求断开连接。
- 客户端收到FIN包后,向服务器发送ACK包,表示确认收到请求,断开连接。
三次握手和四次挥手是TCP协议中非常重要的机制,它们保证了数据传输的可靠性和完整性。在实际的网络通信中,它们被广泛应用于各种应用场景中,如网页浏览、文件传输、邮件发送等。
6.rabbitMq在项目中的作用?
RabbitMQ是一个开源的消息队列中间件,它在项目中有以下几个作用:
-
解耦:RabbitMQ可以将消息的发送者和接收者解耦,发送者只需要将消息发送到消息队列中,而不需要直接与接收者进行交互。这样可以降低系统之间的耦合度,提高系统的可维护性和可扩展性。
-
异步处理:RabbitMQ可以实现异步处理,发送者将消息发送到消息队列后,就可以继续处理其他任务,而不需要等待接收者的响应。这样可以提高系统的并发能力和响应速度。
-
削峰填谷:在高并发的情况下,如果直接将请求发送给接收者,可能会导致接收者无法处理过多的请求而崩溃。而使用RabbitMQ可以将请求发送到消息队列中,然后由多个接收者进行消费,从而平均分摊请求压力,避免系统崩溃。
-
消息持久化:RabbitMQ支持消息的持久化,即将消息存储到磁盘上,即使在RabbitMQ重启后也不会丢失消息。这对于一些重要的消息来说非常重要,可以确保消息的可靠性传输。
-
顺序性:RabbitMQ可以保证消息的顺序性,即发送的消息按照发送的顺序被接收者消费。这对于一些需要按照顺序处理的任务来说非常重要。
总之,RabbitMQ在项目中的作用非常广泛,可以提高系统的可靠性、可扩展性和性能,并且能够解决分布式系统中的一些常见问题。
7.说说什么叫做微服务的服务治理?
微服务的服务治理是指在微服务架构中,对服务进行管理和控制的一系列机制和策略。它主要包括以下几个方面:
-
服务注册与发现:微服务架构中的每个服务都需要向服务注册中心注册自己的信息,包括服务的地址、端口等。同时,其他服务可以通过服务注册中心来发现和获取需要调用的服务的信息,实现服务之间的解耦。
-
负载均衡:微服务架构中的服务可能会有多个实例,负载均衡机制可以根据一定的策略将请求均匀地分发到各个实例上,从而实现负载的均衡,提高系统的性能和可扩展性。
-
故障熔断与容错:在微服务架构中,一个服务的故障可能会影响到其他服务的正常运行。服务治理可以通过故障熔断和容错机制来保护系统的稳定性。当一个服务发生故障时,可以及时地将请求转发到备用服务上,避免故障的扩散。
-
隔离与限流:在微服务架构中,不同的服务可能具有不同的性能和资源消耗。服务治理可以通过隔离和限流机制,对不同的服务进行资源的划分和调度,保证资源的合理利用和系统的稳定性。
-
监控与追踪:微服务架构中的每个服务都需要进行监控和追踪,以便及时发现和解决问题。服务治理可以提供监控和追踪的功能,对服务的运行状态进行实时监控,并记录和分析服务的调用链路,以便进行故障排查和性能优化。
综上所述,微服务的服务治理是对微服务架构中的服务进行管理和控制的一系列机制和策略,它能够提高系统的可靠性、可扩展性和性能,并且能够解决分布式系统中的一些常见问题。
第二天
1.jvm中常见的垃圾清除算法有哪些?
-
标记-清除(Mark and Sweep)算法:该算法分为两个阶段。首先,从根对象开始,标记所有可达对象。然后,在清除阶段,清除未标记的对象,回收它们所占用的内存空间。标记-清除算法会产生内存碎片,可能会导致内存分配效率降低。
-
复制(Copying)算法:该算法将堆内存分为两个区域,一半为活动对象区域,一半为空闲区域。首先,将活动对象从一个区域复制到另一个区域,然后清除整个区域。复制算法解决了内存碎片问题,但需要额外的空间来存储复制过程中的对象。
-
标记-整理(Mark and Compact)算法:该算法结合了标记-清除和复制算法的优点。首先,标记所有可达对象。然后,将所有存活的对象向一端移动,然后清除剩余的空间。标记-整理算法可以解决内存碎片问题,并且不需要额外的空间。
-
分代(Generational)算法:该算法基于一个观察:大部分对象的生命周期较短。因此,堆内存被划分为几个代(Generation),每个代有不同的生命周期。通常将新对象分配在年轻代,而较长生命周期的对象则分配在老年代。不同的代可以使用不同的垃圾清除算法,如年轻代使用复制算法,老年代使用标记-整理算法。
这些垃圾清除算法在不同的情况下有不同的优势和劣势。JVM通常会根据堆内存的特征和应用程序的行为动态选择和调整垃圾清除算法,以达到最佳的性能和内存利用率。
2.java中引用类型分别是什么,有什么特征?
-
强引用(Strong Reference):强引用是最常见的引用类型。当一个对象被强引用引用时,它不会被垃圾回收器回收,即使内存空间紧张。只有当没有任何强引用指向一个对象时,该对象才会被认为是不可达的,从而可以被垃圾回收。
-
软引用(Soft Reference):软引用是一种相对较弱的引用类型。当内存空间紧张时,垃圾回收器可能会回收软引用指向的对象。软引用通常用于实现内存敏感的缓存,当内存不足时,可以回收一些缓存对象来释放内存。
-
弱引用(Weak Reference):弱引用是一种更弱的引用类型。垃圾回收器会更容易回收弱引用指向的对象,即使内存空间不紧张。弱引用通常用于实现辅助数据结构,如WeakHashMap,当对象的弱引用被回收时,相关的数据也可以被清理。
-
虚引用(Phantom Reference):虚引用是最弱的引用类型。虚引用主要用于跟踪对象被垃圾回收的状态。虚引用不能直接访问对象,也不能通过虚引用获取对象的值。它通常与引用队列(ReferenceQueue)一起使用,当对象被垃圾回收时,会将虚引用加入到引用队列中,从而可以在对象被回收时进行一些特定的处理操作。
这些引用类型的特点如下:
- 强引用:强引用是默认的引用类型,它们在程序中随处可见,并且可以直接访问对象。
- 软引用:软引用是一种在内存不足时可以被回收的引用,适用于缓存等场景。
- 弱引用:弱引用是一种更弱的引用类型,垃圾回收器更容易回收弱引用指向的对象。
- 虚引用:虚引用是一种最弱的引用类型,主要用于跟踪对象被垃圾回收的状态,不能直接访问对象。
引用类型的选择取决于具体的应用场景和需求。
3.ArrayList和LinkList的区别有哪些?
-
底层实现:ArrayList是基于数组实现的,LinkedList是基于双向链表实现的。
-
访问效率:ArrayList的访问效率比LinkedList高,因为ArrayList是基于数组实现的,可以通过索引直接访问元素,时间复杂度为O(1);而LinkedList需要从头或尾开始遍历链表,时间复杂度为O(n)。
-
插入和删除效率:LinkedList的插入和删除效率比ArrayList高,因为LinkedList是基于链表实现的,插入和删除元素只需要改变相邻节点的指针,时间复杂度为O(1);而ArrayList需要移动元素,时间复杂度为O(n)。【ArrayList查询快 增删慢 LinkedList查询慢 增删快】
-
内存占用:ArrayList的内存占用比LinkedList高,因为ArrayList需要预分配一段连续的内存空间,而LinkedList只需要为每个节点分配内存。【ArrayList内存占用高 LinkedList内存占用低】
-
随机访问和顺序访问:ArrayList适合随机访问,可以通过索引快速访问任意位置的元素;LinkedList适合顺序访问,可以高效地在头部或尾部插入和删除元素。
综上所述,如果需要频繁进行随机访问操作,或者对内存占用有要求,可以选择ArrayList;如果需要频繁进行插入和删除操作,或者对访问效率要求不高,可以选择LinkedList。
4.Set中如何使用equals()与hashCode()的?
在Set中使用equals()和hashCode()的目的是为了确保Set中的元素是唯一的。当向Set中添加元素时,Set会首先调用元素的hashCode()方法来获取元素的哈希码值,然后根据哈希码值判断元素是否已经存在于Set中。如果哈希码值相同,Set会继续调用元素的equals()方法来比较元素是否相等。只有当哈希码值相等且equals()方法返回true时,Set才会认为元素已经存在于Set中,不会将其重复添加。
5.多线程中start与run区别?
-
start()方法:
- 用于启动一个新线程,并让该线程执行run()方法中的代码。
- 在调用start()方法后,会创建一个新的线程,并使其处于就绪状态,等待CPU调度执行。
- start()方法会立即返回,并不会等待线程执行完毕。
-
run()方法:
- 是Thread类中的一个普通方法,用于定义线程的执行逻辑。
- 在start()方法启动的新线程中,会自动调用run()方法,并执行其中的代码。
- run()方法的执行是在当前线程中进行的,而不是在新线程中执行。
- run()方法会按照顺序依次执行,直到方法结束或线程被中断。
总结:
- start()方法用于启动一个新线程,让新线程执行run()方法中的代码。
- run()方法是线程的执行逻辑,会在新线程中自动调用,也可以在当前线程中手动调用。
- 在多线程编程中,应该使用start()方法来启动线程,而不是直接调用run()方法。因为直接调用run()方法不会创建新线程,而是在当前线程中执行,无法实现多线程的并发执行。
6.什么是乐观锁(版本锁)。什么是悲观锁(行锁) [不知道如何回答]
乐观锁:在数据库中查询数据后会得到一个版本号 然后对数据进行修改 修改完成之后 会查看数据库此时的数据的版本号是否发生了改变,如果没有,则将修改之后的数据放入数据库;如果改了,则再次查询数据库的版本号,重复上次操作,直到未更改为止,最好将版本号加一。
悲观锁:在查询数据库中,当他修改数据库时后给这个查询加上锁(?),其他人无法访问这个数据库,只有修改完之后,解锁了才可以访问。悲观锁使用表锁和行锁,易死锁
7.java中的反射机制是指什么,常用api有哪些?
csdn的博客: Java反射常用API-CSDN博客
Java中的反射机制是指在运行时动态地获取类的信息,并能够操作类或对象的属性、方法、构造方法等。通过反射机制,可以在程序运行时动态地创建对象、调用方法、获取属性值等,而不需要在编译时确定。
常用的反射API包括:
-
Class类:表示一个类或接口,在运行时可以通过该类获取类的信息,如类名、父类、接口、构造方法、成员变量、方法等。
-
Constructor类:表示一个构造方法,在运行时可以通过该类创建对象。
-
Method类:表示一个方法,在运行时可以通过该类调用方法。
-
Field类:表示一个成员变量,在运行时可以通过该类获取和设置成员变量的值。
-
Modifier类:用于获取成员变量、方法、构造方法的修饰符信息。
通过反射机制,可以实现很多动态化的功能,如动态代理、IOC容器、ORM框架等。但是由于反射机制需要在运行时进行类型检查和方法调用,因此会带来一定的性能损失,同时也会降低代码的可读性和可维护性,因此在使用反射机制时需要谨慎。
获取反射的三种方式如下:
1.通过对象的getClass()方法获取反射:可以通过已有的对象调用getClass()方法获取其对应的Class对象。例如:
String str = "Hello"; Class<?> cls = str.getClass();
2.通过类名.class获取反射:可以直接使用类名后加上.class来获取对应的Class对象。例如:
Class<?> cls = String.class;
3.通过Class.forName()方法获取反射:可以使用Class类的静态方法forName(),传入类的完全限定名来获取对应的Class对象。例如:
Class<?> cls = Class.forName("java.lang.String");
需要注意的是,通过这三种方式获取的Class对象都可以用于进行反射操作,但是在实际应用中,根据具体的场景和需求选择合适的方式。
8.Spring核心组件有哪些,什么作用?
-
IoC容器:IoC(Inversion of Control)是Spring的核心思想,它通过容器来管理对象的生命周期和依赖关系,实现了对象之间的解耦。Spring的IoC容器提供了依赖注入(DI)和面向切面编程(AOP)等功能,可以大大简化应用程序的开发和维护。
-
AOP框架:AOP(Aspect Oriented Programming)是一种编程思想,它可以将横切逻辑(如日志、事务、安全等)与业务逻辑分离,使得应用程序更加模块化和可维护。Spring的AOP框架基于代理模式实现,支持基于注解和XML配置的切面编程。
-
JDBC框架:JDBC(Java Database Connectivity)是Java访问关系型数据库的标准API,Spring的JDBC框架基于JDBC API封装了一系列的模板类和回调接口,使得数据库访问更加简单、安全和高效。
-
ORM框架:ORM(Object Relational Mapping)是一种将关系型数据库映射为对象的技术,它可以将Java对象和数据库表之间建立映射关系,使得对象的持久化更加方便。Spring的ORM框架支持多种ORM实现,如Hibernate、MyBatis等。(对象关系映射框架)
-
Web框架:Spring的Web框架提供了一系列的模块,如Spring MVC、Spring WebFlux等,用于简化Web应用程序的开发和测试。
-
测试框架:Spring的测试框架提供了一系列的测试工具和模拟对象,如JUnit、Mockito等,用于简化单元测试和集成测试的开发和调试
Spring的核心组件提供了一系列的功能和特性,用于简化企业级应用开发的复杂性,提高应用程序的可维护性、可测试性和可扩展性。同时,Spring还提供了一系列的扩展模块和整合模块,用于与其他技术和框架进行集成,如Spring Boot、Spring Cloud等。
9.springAop两种代理方式
Spring AOP提供了两种代理方式:基于接口的代理和基于类的代理。
-
基于接口的代理:这种代理方式是通过JDK的动态代理实现的。当目标对象实现了接口时,Spring AOP将使用JDK的动态代理来创建代理对象。代理对象实现了目标对象所实现的接口,并将方法的调用委托给目标对象。这种代理方式要求目标对象实现接口,因此只能代理实现了接口的类。
-
基于类的代理:这种代理方式是通过CGLIB(Code Generation Library)实现的。当目标对象没有实现接口时,Spring AOP将使用CGLIB来创建代理对象。代理对象继承了目标对象,并重写了目标对象的方法。这种代理方式可以代理没有实现接口的类。
Spring AOP会自动选择合适的代理方式,如果目标对象实现了接口,则使用基于接口的代理;如果目标对象没有实现接口,则使用基于类的代理。开发者无需关心具体的代理方式,只需要按照需要编写切面和通知即可。
10.springmvc常用注解
Spring MVC是Spring框架的一部分,用于开发基于MVC(Model-View-Controller)架构的Web应用程序。在Spring MVC中,常用的注解包括:
-
@Controller:用于标识一个类是控制器,处理用户的请求并返回相应的结果。
-
@RequestMapping:用于将请求URL映射到控制器的处理方法上。
-
@GetMapping:用于将GET请求映射到控制器的处理方法上。
-
@PostMapping:用于将POST请求映射到控制器的处理方法上。
-
@PutMapping:用于将PUT请求映射到控制器的处理方法上。
-
@DeleteMapping:用于将DELETE请求映射到控制器的处理方法上。
-
@PathVariable:用于获取URL路径中的参数值。
-
@RequestParam:用于获取请求参数的值。
-
@RequestBody:用于将请求体中的数据绑定到方法参数上。
-
@ResponseBody:用于将方法返回的结果转换为指定格式(如JSON、XML)并作为响应内容返回给客户端。
-
@ModelAttribute:用于将请求参数绑定到模型对象上。
-
@SessionAttribute:用于将模型对象存储到Session中。
-
@Valid:用于对方法参数进行数据校验。
-
@ExceptionHandler:用于处理异常,将异常信息转换为指定格式并返回给客户端。
-
@RestController: 是一个用于标识控制器类的注解,它是 Spring MVC 中的一个特殊注解,结合了 @Controller 和 @ResponseBody 注解的功能。使用 @RestController 注解的类将自动将方法的返回值转换为 JSON 或 XML 格式的响应数据。
以上是Spring MVC中常用的注解,通过使用这些注解,可以方便地开发和管理Web应用程序的请求处理逻辑。
11.spring中用到哪些设计模式?
-
单例模式:Spring框架中的Bean默认是单例的,通过IoC容器管理,保证了每个Bean只有一个实例。
-
工厂模式:Spring使用工厂模式来创建和管理Bean对象,通过IoC容器中的BeanFactory或ApplicationContext来创建和获取Bean实例。
-
代理模式:Spring AOP使用代理模式实现切面编程,通过代理对象来增强目标对象的功能。
-
观察者模式:Spring中的事件机制使用了观察者模式,通过事件发布者和事件监听者的关系,实现了解耦和事件的传递。
-
模板模式:Spring中的JdbcTemplate和HibernateTemplate等模板类使用了模板模式,将通用的模板代码封装起来,简化了数据库访问和持久化操作。
-
适配器模式:Spring MVC中的HandlerAdapter使用了适配器模式,将不同类型的处理器适配为统一的处理器接口。
-
策略模式:Spring中的IOC容器使用了策略模式,根据配置文件或注解来选择不同的实现策略。
-
装饰器模式:Spring中的AOP使用了装饰器模式,通过动态代理来增强目标对象的功能。
12.http常用状态有哪些,代表什么意思?
- 1xx(信息类):表示请求已被接收,继续处理。
- 100(Continue):服务器已接收到请求的一部分,客户端可以继续发送剩余的请求。
- 2xx(成功类):表示请求已成功被服务器接收、理解和处理。
-
200(OK):请求成功,服务器正常返回请求的数据。
-
201(Created):请求已经被成功处理,并创建了新的资源。
-
204(No Content):服务器成功处理了请求,但没有返回任何内容。
- 3xx(重定向类):表示需要进一步操作以完成请求。
-
301(Moved Permanently):永久重定向,请求的资源已被永久移动到新的URL。
-
302(Found):临时重定向,请求的资源临时移动到新的URL。
-
304(Not Modified):请求的资源未修改,可以使用缓存的版本。
- 4xx(客户端错误类):表示请求包含语法错误或无法完成请求。
-
400(Bad Request):请求无效,服务器无法理解。
-
401(Unauthorized):请求要求身份验证。
-
403(Forbidden):服务器拒绝请求。
-
404(Not Found):请求的资源不存在。
- 5xx(服务器错误类):表示服务器在处理请求时发生了错误。
-
500(Internal Server Error):服务器内部错误。
-
502(Bad Gateway):服务器作为网关或代理,从上游服务器收到无效响应。
-
503(Service Unavailable):服务器当前无法处理请求,一段时间后可能恢复正常。
13.你熟系的加密算法有哪些?
-
对称加密算法:使用相同的密钥进行加密和解密,常见的对称加密算法有DES、3DES、AES等。
-
非对称加密算法:使用一对密钥,公钥用于加密,私钥用于解密,常见的非对称加密算法有RSA、ECC等。
-
哈希算法:将任意长度的数据转换为固定长度的哈希值,常见的哈希算法有MD5、SHA-1、SHA-256等。
-
消息认证码(MAC):使用密钥对消息进行加密,并生成一个固定长度的认证码,常见的MAC算法有HMAC、CMAC等。
-
数字签名算法:使用私钥对消息进行签名,然后使用公钥进行验证,常见的数字签名算法有RSA、DSA、ECDSA等。
-
Base64算法:一种用于将二进制数据转换为可打印字符的编码算法。它将3个字节的数据分为4个6位的组,并将每个6位组映射到一个可打印字符。由于每个可打印字符占8位,所以Base64编码后的数据长度会比原始数据稍长。
第三天
1.接口和抽象类的区别是什么?
2.String、StringBuffer和StringBuilder的区别?
3.什么是死锁?
死锁是指在并发计算中,两个或多个进程或线程因争夺系统资源而陷入无限等待的状态,无法继续执行下去,导致系统无法正常运行。死锁通常发生在多个进程或线程同时持有某些资源,并且互相等待对方释放资源的情况下。当发生死锁时,系统无法进行进一步的处理,只能通过强制终止进程或线程来解决问题。
4.equals()和hashcode()的用法?
equals()和hashCode()是Java中Object类的两个方法,用于比较对象的相等性和生成对象的哈希码。
equals()方法用于判断两个对象是否相等。默认情况下,equals()方法比较的是对象的引用是否相等,即比较两个对象是否指向同一个内存地址。但是,我们可以根据实际需求重写equals()方法,自定义比较规则。重写equals()方法时需要遵循以下几个原则:
- 自反性:对于任意非空对象x,x.equals(x)应该返回true。
- 对称性:对于任意非空对象x和y,如果x.equals(y)返回true,则y.equals(x)也应该返回true。
- 传递性:对于任意非空对象x、y和z,如果x.equals(y)返回true,并且y.equals(z)返回true,则x.equals(z)也应该返回true。
- 一致性:对于任意非空对象x和y,如果对象没有发生变化,那么多次调用x.equals(y)应该返回相同的结果。
- 非空性:对于任意非空对象x,x.equals(null)应该返回false。
{equals()方法使用如下:
a) 系统类一般已经覆盖了equals(),比较的是内容。
b) 用户自定义类如果没有覆盖equals(),将调用父类的equals (比如是Object),而Object的equals的比较是地址(return (this == obj);)
c) 用户自定义类需要覆盖父类的equals()
注意:Object的==和equals比较的都是地址,作用相同}
hashCode()方法用于生成对象的哈希码。哈希码是一个整数值,用于在哈希表等数据结构中快速查找对象。hashCode()方法的实现应该保证以下几个原则:
- 如果两个对象通过equals()方法比较相等,那么它们的hashCode()方法应该返回相同的值。
- 如果两个对象通过equals()方法比较不相等,那么它们的hashCode()方法返回的值可以相同,也可以不同,但是不相等的对象尽量返回不同的哈希码,以提高哈希表的性能。
在重写equals()方法时,通常也需要同时重写hashCode()方法,以保证对象在集合类中的正确使用,比如HashSet、HashMap等。
5.cookies与session的区别与联系?
Cookies和Session是用于在Web应用程序中跟踪用户状态的机制,它们有一些区别和联系。
区别:
- 存储位置:Cookies存储在客户端(浏览器)中,而Session存储在服务器端。
- 容量限制:Cookies的容量通常较小,一般为4KB左右,而Session的容量相对较大,可根据服务器配置进行调整。
- 安全性:Cookies的数据在客户端存储,容易被窃取或篡改,因此不适合存储敏感信息;而Session的数据存储在服务器端,相对更安全。
- 生命周期:Cookies可以设置过期时间,可以在客户端存储一段时间;而Session通常在用户关闭浏览器或一段时间不活动后会自动过期。
联系:
- 数据传递:Cookies和Session都可以用于在不同的HTTP请求之间传递数据,以维持用户的状态。
- 用户识别:Cookies和Session都可以用于识别用户,以区分不同的用户请求。
- 存储方式:Cookies和Session都可以存储复杂的数据结构,如对象、数组等。
综上所述,Cookies适合存储小量的非敏感数据,而Session适合存储较大量的敏感数据。在实际应用中,Cookies和Session通常会结合使用,通过Cookies存储Session的标识符来实现用户状态的跟踪和管理。
6.什么是数据库索引,索引设计的规则。
数据库索引是一种数据结构,用于加快数据库查询操作的速度。它类似于书籍的目录,可以通过索引快速定位到所需的数据,而不需要遍历整个数据表。
索引设计的规则包括以下几个方面:
- 唯一性:索引的值应该是唯一的,以确保每个索引值对应的数据记录都是唯一的。如果索引值不唯一,可能会导致查询结果不准确或冲突。
- 精确性:索引应该准确地反映数据表中的数据,以保证查询的准确性。如果索引不准确,可能会导致查询结果不完整或错误。
- 稳定性:索引的值应该是稳定的,不会频繁变动。如果索引值经常变动,可能会导致索引失效或性能下降。
- 多样性:索引应该涵盖不同的查询条件,以满足不同的查询需求。如果索引过于单一,可能无法满足多样化的查询需求。
- 大小适中:索引的大小应该适中,既能提高查询速度,又不会占用过多的存储空间。如果索引过大,可能会影响查询性能和存储空间。
- 更新频率:索引的更新频率应该适中,既能保证查询性能,又能及时反映数据的变化。如果索引更新频率过高,可能会影响写操作的性能。
综上所述,索引设计需要考虑唯一性、精确性、稳定性、多样性、大小适中和更新频率等因素,以提高查询性能和准确性。在实际应用中,根据具体的业务需求和数据特点,选择合适的字段作为索引,并对索引进行适当的优化和调整。
7.char和varchar的区别
char和varchar是两种常见的字符串数据类型,它们在存储方式和使用上有一些区别。
-
存储方式:
- char:char类型是固定长度的字符串类型,需要指定长度。无论实际存储的字符串长度是否达到指定长度,char类型的字段都会占用指定长度的存储空间。例如,char(10)类型的字段,无论实际存储的字符串是"abc"还是"abcdefghij",都会占用10个字符的存储空间。
- varchar:varchar类型是可变长度的字符串类型,也需要指定最大长度。varchar类型的字段只会占用实际存储的字符串长度加上额外的存储空间来记录字符串长度的字节。例如,varchar(10)类型的字段,如果存储的字符串是"abc",则只会占用3个字符的存储空间。
-
存储效率:
- char:由于char类型是固定长度的,所以在存储时会占用固定大小的存储空间,无论实际存储的字符串长度是多少。这在一些需要频繁更新或插入的场景下可能会浪费存储空间。
- varchar:由于varchar类型是可变长度的,所以在存储时只会占用实际存储的字符串长度加上额外的存储空间来记录字符串长度的字节。这在存储长度不固定的字符串时可以节省存储空间。
-
使用上的限制:
- char:由于char类型是固定长度的,所以在存储时需要保证实际存储的字符串长度不超过指定长度,否则会被截断。(不能超过固定长度)
- varchar:varchar类型没有固定长度的限制,可以存储任意长度的字符串。
综上所述,char和varchar在存储方式和使用上有一些区别,选择使用哪种类型取决于实际的需求和场景。如果字符串长度固定且较小,可以考虑使用char类型;如果字符串长度不固定或较大,可以考虑使用varchar类型。
8.MyISAM和InnoDB的区别?
1、MyIASM 是非事务安全的,而 InnoDB 是事务安全的
2、MyIASM 锁的粒度是表级的,而 InnoDB 支持行级锁
3、MyIASM 支持全文类型索引,而 InnoDB 不支持全文索引
4、MyIASM 相对简单,效率上要优于 InnoDB,小型应用可以考虑使用 MyIASM
5、MyIASM 表保存成文件形式,跨平台使用更加方便
9.spring中的bean有几种scope(作用域),分别代表什么意思?
11.简单的谈一下SpringMVC的工作流程?
-
客户端发送请求:客户端(通常是浏览器)发送HTTP请求到服务器。
-
DispatcherServlet接收请求:DispatcherServlet是Spring MVC的核心控制器,它接收所有的请求并将其分发给相应的处理器。
-
处理器映射器进行映射:处理器映射器(HandlerMapping)根据请求的URL路径,将请求映射到相应的处理器(Controller)。
-
处理器执行请求:处理器(Controller)根据业务逻辑处理请求,并生成模型数据和视图名称。
-
视图解析器解析视图:视图解析器(ViewResolver)根据视图名称解析出具体的视图对象。
-
视图渲染:视图对象将模型数据渲染到具体的视图上,生成最终的HTML响应。
-
响应返回给客户端:最终生成的HTML响应通过HTTP响应返回给客户端。
13.mybatis#和$的区别?
14.myBatis中常用的动态标签库及其作用?
-
if:用于条件判断,根据条件动态生成SQL语句的一部分。
-
choose/when/otherwise:类似于Java中的switch语句,根据条件选择不同的分支。
-
trim:用于去除生成的SQL语句中的多余的空格或逗号。
-
where:用于在生成的SQL语句中添加WHERE子句,根据条件动态生成查询条件。
-
set:用于在生成的SQL语句中添加SET子句,根据条件动态生成更新字段。
-
foreach:用于循环遍历集合或数组,生成动态的SQL语句。
这些动态标签的作用是为了在SQL语句中根据条件动态生成不同的部分,以实现灵活的查询和更新操作。通过使用这些动态标签,可以避免在Java代码中拼接SQL语句,提高代码的可读性和可维护性。同时,MyBatis的动态标签还能够有效地防止SQL注入攻击,提高系统的安全性。
15.什么是微服务,微服务与普通项目好处在哪些地方?
微服务是一种架构风格,它将一个大型的应用程序拆分成一组小型的、相互独立的服务。每个服务都可以独立地开发、部署和扩展,可以使用不同的编程语言和技术栈。这些服务之间通过轻量级的通信机制进行通信,例如RESTful API、消息队列等。微服务架构强调每个服务的自治性,服务之间松耦合,可以独立进行开发、测试、部署和扩展。
与传统的单体应用程序相比,微服务架构具有以下优势:
-
松耦合:微服务之间通过轻量级的通信机制进行通信,彼此之间没有强依赖关系。这使得每个服务可以独立开发、测试、部署和扩展,不会影响其他服务的运行。
-
独立部署:每个微服务都可以独立部署,可以根据需要对某个服务进行更新或扩展,而不会影响整个应用程序。
-
技术多样性:由于每个服务都可以使用不同的编程语言和技术栈,开发团队可以选择最适合自己的技术来实现服务。这样可以更好地利用团队的技术能力和偏好。
-
可扩展性:微服务架构可以根据需求对某个服务进行水平扩展,只需要增加相应的服务实例即可。这样可以更好地应对高并发和大流量的情况。
-
容错性:由于每个服务都是相互独立的,当某个服务发生故障时,不会影响整个应用程序的运行。其他服务仍然可以正常工作,提高了应用程序的容错性和可用性。
-
高内聚:每个微服务都关注于特定的业务功能,具有高内聚性。这样可以更好地组织代码和维护代码,使得应用程序更易于理解和扩展。
总的来说,微服务架构可以提高应用程序的灵活性、可伸缩性和可维护性,使得团队可以更快地开发和交付新的功能。然而,微服务架构也带来了一些挑战,如服务之间的通信、服务的发现和治理、分布式事务等问题需要额外的考虑和解决。
16.springcloud常用组件及其作用。
Ribbon(RestTemplate)/Feign:客户端负载均衡/声明性(接口)的Web服务客户端
Hystrix/sentinel/Resilience4j:断路器:防止雪崩效应(不同于缓存雪崩)
Config:分布式统一配置管理/nacos
17.Redis 的持久化机制是什么?各自的优缺点?
什么是Redis持久化? 持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。
Redis有两种持久化机制:RDB(Redis Database)和AOF(Append-Only File)。
-
RDB持久化机制:
- 优点:
- 性能高:RDB是将Redis的数据以二进制格式快照保存到硬盘上,恢复数据时只需要加载快照文件即可,速度非常快。
- 文件紧凑:RDB文件是一个紧凑的二进制文件,适合用于备份和迁移。
- 缺点:
- 数据丢失:由于RDB是定期进行快照保存的,如果Redis在最后一次快照之后发生故障,可能会丢失最后一次快照之后的数据。
- 高延迟:当Redis数据集较大时,进行RDB快照可能会导致Redis进程阻塞一段时间,造成高延迟。
- 不适合实时备份:由于RDB是定期进行快照保存的,不适合对数据进行实时备份。
- 优点:
-
AOF持久化机制:
- 优点:
- 数据安全:AOF以追加的方式记录每个写操作,保证了数据的安全性,即使Redis进程崩溃,也可以通过重放AOF日志来恢复数据。
- 实时备份:AOF可以实时记录每个写操作,可以通过设置合适的fsync策略来保证数据的实时备份。
- 缺点:
- 文件较大:AOF文件相对于RDB文件来说较大,如果数据集较大,AOF文件会占用较多的磁盘空间。
- 恢复速度慢:由于AOF文件较大,恢复数据时需要加载整个AOF文件,速度相对较慢。
- 对硬盘的IO压力较大:AOF以追加的方式记录每个写操作,对硬盘的IO压力较大,可能会影响性能。
- 优点:
综上所述,RDB适用于对数据一致性要求不高、对性能要求较高的场景,如备份和迁移;AOF适用于对数据一致性要求较高、对实时备份和恢复要求较高的场景。根据实际需求,可以选择合适的持久化机制或者同时使用两种机制来提高数据的安全性和可靠性。
18.什么是雪崩效应,如何防止雪崩效应,原理是什么?
19.spring的自动配置原理是什么?
:加注解@nableAutoConfiguration
20.什么是Tcp/ip和UDP?
TCP/IP(Transmission Control Protocol/Internet Protocol)是一种面向连接的协议,它提供了可靠的数据传输和网络通信服务。TCP协议负责将数据分割成小的数据包,并确保它们按顺序到达目标地址,同时还提供了流量控制和拥塞控制等机制。IP协议负责将数据包从源地址传输到目标地址,它定义了数据包的格式和路由选择规则。
UDP(User Datagram Protocol)是一种无连接的协议,它提供了不可靠的数据传输和网络通信服务。UDP协议不保证数据包的顺序和可靠性,数据包可能会丢失或重复,但它的传输速度相对较快。UDP适用于实时性要求较高的应用,如音频、视频和实时游戏等。
TCP/IP和UDP都是在网络层以上的传输层协议,它们通过IP地址和端口号来标识通信的源和目标。TCP/IP适用于需要可靠传输和有序数据的应用,如网页浏览、文件传输和电子邮件等;而UDP适用于需要快速传输和实时性要求较高的应用,如实时音视频传输和即时通信等。
总的来说,TCP/IP和UDP是计算机网络中常用的传输协议,根据应用的需求选择合适的协议可以提高网络通信的效率和性能。
第四天
2.java运行时异常与受检异常有何异同?
Java中的异常分为运行时异常(RuntimeException)和受检异常(Checked Exception)。它们之间有以下几个主要的异同点:
-
检查与非检查:受检异常是在编译时强制要求处理的异常,而运行时异常是不需要在编译时处理的异常。如果一个方法可能会抛出受检异常,那么调用该方法的代码必须要么捕获该异常并处理,要么在方法声明中使用throws关键字声明该异常。而对于运行时异常,可以选择性地捕获和处理,也可以不处理。
-
继承关系:运行时异常是RuntimeException类及其子类的实例,而受检异常是Exception类及其子类中除了RuntimeException的其他子类的实例。因此,运行时异常属于非受检异常,而受检异常属于受检异常。
-
异常类型:运行时异常通常表示程序运行时的错误或异常情况,如空指针异常(NullPointerException)、数组越界异常(ArrayIndexOutOfBoundsException)等。受检异常通常表示外部环境或资源的异常情况,如文件不存在(FileNotFoundException)、网络连接异常(IOException)等。
-
异常处理:对于受检异常,必须显式处理或者通过throws关键字声明,否则编译器会报错。而对于运行时异常,可以选择性地处理或者不处理,编译器不会强制要求处理。【受检异常 必须throws 运行可处理可不处理】
总的来说,运行时异常和受检异常的主要区别在于编译器对它们的处理要求不同。受检异常必须要求在编译时处理,而运行时异常可以选择性地处理或不处理。在实际开发中,通常建议对于受检异常进行适当的处理,而对于运行时异常则可以根据具体情况决定是否处理。
3.“a==b”和“a.equals(b)”有什么区别?“==”是关系运算符,equals()是方法,同时他们的结果都返回布尔值;
“==”使用情况如下:
a) 基本类型,比较的是值
b) 引用类型,比较的是地址
c) 不能比较没有父子关系的两个对象
equals()方法使用如下:
a) 系统类一般已经覆盖了equals(),比较的是内容。
b) 用户自定义类如果没有覆盖equals(),将调用父类的equals (比如是Object),而Object的equals的比较是地址(return (this == obj);)
c) 用户自定义类需要覆盖父类的equals()
注意:Object的==和equals比较的都是地址,作用相同
4.在spring中什么是“依赖注入”和“控制反转”?
在Spring框架中,"依赖注入"(Dependency Injection)和"控制反转"(Inversion of Control)是两个核心概念。
依赖注入是一种设计模式,它通过将对象的依赖关系从代码中硬编码的方式转移到外部容器中来实现。简而言之,依赖注入是指对象不再自己创建或管理它所依赖的对象,而是由外部容器负责创建和注入依赖对象。这样做的好处是,对象之间的依赖关系变得松散耦合,更容易进行单元测试、模块化和可重用性。
控制反转是依赖注入的一种实现方式,它通过将对象的创建和依赖注入的控制权从应用程序代码中转移到外部容器中来实现。简而言之,控制反转是指应用程序不再负责创建和管理对象,而是将这些责任交给外部容器。外部容器负责创建对象,并将依赖注入到需要的地方。这样做的好处是,应用程序的代码变得更加简洁和可读,同时也提高了代码的可测试性和可维护性。
在Spring框架中,依赖注入和控制反转是通过IoC容器来实现的。IoC容器负责管理对象的生命周期、创建对象、解决对象之间的依赖关系,并将依赖注入到需要的地方。Spring框架提供了多种依赖注入的方式,包括构造函数注入、setter方法注入和注解注入等。开发人员可以根据具体的需求选择适合的依赖注入方式。
5.说出5个jdk1.8引入的新特性?
1、Lamdba表达式
Lambda 表达式是一种简洁的语法,用于表示匿名函数。它允许我们以更简洁的方式编写函数式接口的实现。Lambda 表达式可以使代码更加简洁、易读,并且可以更好地支持并发编程。
2、函数式接口
只包含一个抽象方法的接口,称为函数式接口,并且可以使用lambda表达式来创建该接口的对象,可以在任意函数式接口上使用@FunctionalInterface注解,来检测它是否是符合函数式接口。同时javac也会包含一条声明,说明这个接口是否符合函数式接口。
3、方法引用和构造引用
方法引用是一种更简洁的 Lambda 表达式的写法。它允许我们直接引用已经存在的方法,而不是通过 Lambda 表达式来实现。方法引用可以使代码更加简洁、易读,并且可以提高代码的可维护性。
4、Stream API
Stream API 是一种用于处理集合数据的新方式。它提供了一种声明式的编程模型,可以通过串行或并行的方式对集合进行操作。Stream API 可以帮助我们更加方便地进行数据过滤、转换、排序等操作。
5、接口中的默认方法和静态方法
JDK 1.8 允许在接口中定义默认方法和静态方法。默认方法是接口中的一个具体实现,可以有方法体。静态方法是接口中的一个静态方法,可以直接通过接口名调用。这样可以在不破坏已有代码的情况下,向接口中添加新的方法。
6、新时间日期API
JDK 1.8 引入了新的日期和时间 API,用于替代旧的 Date 和 Calendar 类。新的日期和时间 API 提供了更加简洁、易用的方式来处理日期和时间。它提供了丰富的操作方法,同时也支持时区、日历等功能。
7、OPtional
8、其他特性
6.MySQL中有哪几种锁,都有什么特征?
8.synchronized和reentrantlock的作用和区别?
synchronized和ReentrantLock都是Java中用于实现线程同步的机制,用于保证多个线程之间的互斥访问共享资源。它们的作用和区别如下:
synchronized:
- 作用:synchronized关键字用于修饰方法或代码块,确保在同一时间只有一个线程可以执行被synchronized修饰的方法或代码块。它可以保证线程的安全性,防止多个线程同时访问共享资源造成的数据不一致问题。
- 特点:synchronized是Java内置的关键字,使用方便,但是在某些情况下性能可能不如ReentrantLock。
- 使用方式:可以用于修饰实例方法、静态方法或代码块。当使用synchronized修饰实例方法时,锁定的是当前实例对象;当修饰静态方法时,锁定的是当前类的Class对象;当修饰代码块时,锁定的是括号内指定的对象。
ReentrantLock:
- 作用:ReentrantLock是一个可重入的互斥锁,用于实现更灵活的线程同步。它提供了与synchronized相似的功能,但比synchronized更加灵活,可以实现更复杂的同步需求。
- 特点:ReentrantLock是一个类,提供了更多的功能,比如可中断、可轮询、公平锁等。它需要手动加锁和释放锁,相对于synchronized更加灵活,但也更加复杂。
- 使用方式:通过创建ReentrantLock对象,然后使用
lock()
方法获取锁,使用unlock()
方法释放锁。一般在try-finally
块中使用,确保锁的释放。
区别:
- 锁的获取方式:synchronized是隐式锁,不需要手动获取和释放锁,而ReentrantLock需要手动调用
lock()
方法获取锁,使用unlock()
方法释放锁。 - 锁的灵活性:ReentrantLock提供了更多的功能,比如可中断、可轮询、公平锁等,可以满足更复杂的同步需求;而synchronized的功能相对简单。
- 性能:在低竞争情况下,synchronized的性能可能更好,因为它是JVM内置的关键字,而ReentrantLock是一个类,需要更多的开销。
- 使用场景:一般情况下,推荐使用synchronized,因为它简单易用;只有在需要更高级别的同步需求时,才使用ReentrantLock。
9.实践如何优化Mysql?
优化MySQL的实践可以从多个方面入手,包括优化查询语句、优化表结构、调整配置参数等。以下是一些常见的MySQL优化实践:
-
优化查询语句:
- 使用索引:为经常使用的列添加索引,可以加快查询速度。
- 避免使用SELECT *:只选择需要的列,减少数据传输和处理的开销。
- 使用合适的WHERE条件:使用索引的列作为WHERE条件,可以减少扫描的数据量。
- 避免使用大量的OR语句:使用IN语句代替多个OR语句,可以减少查询的开销。
- 避免使用模糊查询:%开头的模糊查询无法使用索引,尽量避免使用。
-
优化表结构:
- 合理设计表结构:遵循数据库范式,将数据拆分为多个表,减少冗余和重复数据。
- 选择合适的数据类型:使用合适的数据类型,减少存储空间和索引的大小。
- 避免使用过多的JOIN操作:合理设计表关系,避免过多的JOIN操作。
-
调整配置参数:
- 调整缓冲区大小:根据服务器的硬件配置和实际情况,适当调整innodb_buffer_pool_size、key_buffer_size等参数。
- 调整连接数:根据并发连接数的需求,调整max_connections参数。
- 调整日志设置:适当调整日志相关的参数,如slow_query_log、log_queries_not_using_indexes等。
-
使用合适的存储引擎:
- InnoDB引擎:对于事务处理和并发性能要求高的场景,使用InnoDB引擎。
- MyISAM引擎:对于读操作频繁、写操作较少的场景,使用MyISAM引擎。
-
定期优化和维护:
- 定期分析查询执行计划:使用EXPLAIN命令分析查询语句的执行计划,优化查询性能。
- 定期清理无用数据:删除无用的数据,减少数据量,提高查询效率。
- 定期备份和优化表:定期备份数据,优化表结构,减少碎片。
需要注意的是,优化MySQL是一个综合性的工作,需要根据具体的业务场景和实际情况来进行调整和优化。可以通过监控和性能测试工具来评估和验证优化效果,并根据实际情况进行调整和优化。
11.假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如果将它们全部找出来而系统不卡顿?【不会】
13.谈谈你对分布式会话共享的具体实现?【不知道怎么满分】
分布式会话共享是指在分布式系统中,多个节点之间共享用户会话数据,以实现用户在不同节点之间的无缝切换和访问。
具体实现分布式会话共享可以有以下几种方式:
-
使用共享存储:可以使用共享存储(如分布式文件系统、分布式缓存等)来存储会话数据,各个节点通过读写共享存储来获取和更新会话数据。这种方式的优点是简单易实现,但可能存在性能瓶颈和单点故障的问题。
-
使用数据库:可以使用数据库来存储会话数据,各个节点通过读写数据库来获取和更新会话数据。可以使用关系型数据库或者NoSQL数据库来存储数据。这种方式的优点是可靠性高,支持高并发访问,但可能存在数据库性能瓶颈和一致性问题。
-
使用缓存:可以使用分布式缓存(如Redis、Memcached等)来存储会话数据,各个节点通过读写缓存来获取和更新会话数据。缓存具有高性能和高并发访问的特点,适合用于存储会话数据。但需要注意缓存的一致性和容错性。
-
使用消息队列:可以使用消息队列(如Kafka、RabbitMQ等)来实现会话共享。将会话数据以消息的形式发送到消息队列中,各个节点通过订阅消息队列来获取会话数据。这种方式的优点是解耦和异步处理,但可能存在消息丢失和一致性问题。
-
使用分布式缓存框架:可以使用一些分布式缓存框架(如Spring Session、Apache Shiro等)来实现会话共享。这些框架提供了一些封装和工具,可以方便地实现会话共享,并提供了一些特性,如会话管理、会话失效等。
在实现分布式会话共享时,需要考虑以下几个关键问题:
- 一致性:多个节点之间的会话数据需要保持一致,避免数据不一致的问题。
- 容错性:需要考虑节点故障和网络故障的情况,保证会话数据的可用性和可靠性。
- 性能和扩展性:需要考虑并发访问和大规模扩展的情况,保证会话共享的性能和可扩展性。
- 安全性:需要保护会话数据的安全性,防止被恶意篡改或者泄露。
具体选择哪种实现方式,需要根据具体的业务需求和系统架构来进行评估和选择。不同的方式有不同的优缺点,需要根据实际情况进行权衡和取舍。
14.什么是WebSocket?
WebSocket是一种在Web应用程序中实现实时双向通信的协议。它提供了一种在客户端和服务器之间进行全双工通信的方式,使得服务器可以主动向客户端推送数据,而不需要客户端发起请求。
相比于传统的HTTP协议,WebSocket具有以下几个特点:
-
双向通信:WebSocket允许客户端和服务器之间进行双向通信,客户端可以发送消息给服务器,服务器也可以主动推送消息给客户端。
-
实时性:WebSocket提供了低延迟的实时通信能力,适用于需要实时更新数据的应用场景,如聊天应用、实时数据监控等。
-
高效性:WebSocket使用了更轻量级的协议头,减少了数据传输的开销,提高了通信的效率。
-
跨平台支持:WebSocket协议是一种标准化的协议,几乎所有现代浏览器都支持WebSocket,同时也有很多服务器端的实现。
WebSocket的工作原理如下:
-
客户端发起WebSocket连接请求,通过HTTP协议与服务器建立握手。
-
服务器接受握手请求,并返回带有特定标识的响应,表示WebSocket连接已建立。
-
客户端和服务器通过WebSocket协议进行通信,可以发送和接收消息。
-
当连接不再需要时,客户端或服务器可以主动关闭WebSocket连接。
在实际应用中,可以使用WebSocket来实现实时聊天、实时数据推送、在线游戏等功能。同时,为了方便使用WebSocket,许多框架和库(如Socket.IO、Spring WebSocket等)提供了高级的封装和工具,简化了WebSocket的使用和管理。
15.什么是CSRF攻击?
CSRF(Cross-Site Request Forgery)攻击,也称为跨站请求伪造攻击,是一种利用用户在访问恶意网站时的身份验证信息来执行未经授权的操作的攻击方式。
CSRF攻击的原理如下:
-
用户登录一个受信任的网站,并在该网站上获取一个有效的身份验证凭证(如cookie)。
-
用户在未注销或过期的情况下,访问了一个恶意网站。
-
恶意网站中包含了一些针对受信任网站的请求,这些请求会在用户不知情的情况下发送给受信任网站。
-
受信任网站接收到请求后,会将请求当作是用户的合法请求,并执行相应的操作。
CSRF攻击可以导致以下危害:
-
盗取用户的个人信息:攻击者可以通过CSRF攻击来执行一些恶意操作,如修改用户密码、发送钓鱼邮件、购买商品等,从而获取用户的个人信息。
-
以用户身份进行非法操作:攻击者可以利用用户的身份执行一些未经授权的操作,如发表评论、点赞、删除数据等,从而破坏用户的信誉或者造成其他损失。
为了防止CSRF攻击,可以采取以下几种防御措施:
-
验证来源:在服务器端对请求进行验证,确保请求的来源是合法的。可以通过检查请求头中的Referer字段或者使用CSRF令牌来验证请求的合法性。
-
添加随机参数:在每个表单中添加一个随机生成的参数,该参数在提交表单时会一同发送到服务器端,服务器端验证该参数的合法性。
-
使用验证码:对于一些敏感操作,可以要求用户输入验证码来进行验证,增加攻击者的难度。
-
限制权限:合理设置用户的权限和访问控制,限制用户的操作范围,避免恶意操作的发生。
-
定期更新身份验证凭证:及时更新用户的身份验证凭证,避免凭证被攻击者利用。
通过以上防御措施,可以有效防止CSRF攻击的发生。
16.微服务架构的优缺点是什么?
17.mybatis的一级以及、二级缓存。
18.java在a中获取Class对象有几种方法。
-
使用类名.class语法:可以直接使用类名后加上.class来获取对应的Class对象。例如:Class clazz = MyClass.class;
-
使用Class.forName()方法:可以通过传入类的全限定名来获取对应的Class对象。例如:Class clazz = Class.forName("com.example.MyClass");
-
使用对象的getClass()方法:可以通过已有的对象来获取对应的Class对象。例如:MyClass obj = new MyClass(); Class clazz = obj.getClass();
19.谈谈你对数据库索引的认识。
数据库索引是一种数据结构,用于提高数据库查询性能。它是在数据库表中的一列或多列上创建的,通过存储和维护数据的有序副本,加速数据的查找和访问。
索引的作用是快速定位和检索数据,类似于书籍的目录,可以根据关键字快速找到对应的数据记录。在数据库表中,索引可以根据某个或多个列的值来排序和组织数据,从而减少查询时需要扫描的数据量,提高查询的效率。
索引可以提供以下几个方面的优势:
-
提高查询性能:通过使用索引,数据库可以快速定位到满足查询条件的数据,减少了查询时需要扫描的数据量,从而提高了查询的效率。
-
加速排序和分组操作:如果查询需要对结果进行排序或分组,索引可以提供有序的数据副本,减少排序和分组操作的时间。
-
加速连接操作:在进行连接操作时,索引可以加快连接的速度,减少连接操作所需的时间。
-
强制唯一约束:通过在索引上创建唯一约束,可以确保索引列的值是唯一的,避免重复数据的插入。
然而,索引也有一些限制和缺点:
-
占用存储空间:索引需要占用额外的存储空间,特别是在大型表中创建复杂的索引时,可能会占用较多的磁盘空间。
-
增加写操作的时间:在插入、更新和删除数据时,需要维护索引的有序性,可能会增加写操作的时间。
-
索引维护成本:当表中的数据发生变化时,索引需要进行维护,包括插入、删除和更新索引的操作,这些操作可能会增加数据库的负载。
因此,在设计数据库时,需要根据具体的业务需求和查询模式来决定是否创建索引,以及选择合适的索引策略。索引的设计和使用需要权衡查询性能和存储空间的需求,合理使用索引可以提高数据库的性能和响应速度。
20.写一个单例模式
懒汉式单例模式:
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
// 私有构造方法
}
public static synchronized LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
饿汉式单例模式:
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {
// 私有构造方法
}
public static EagerSingleton getInstance() {
return instance;
}
}