1、低代码平台
一种通过可视化界面快速创建应用的平台。常见的有钉钉宜搭和腾讯微搭
- 不用写前端代码,连接数据库,可以直接拖拽
- 只有一些常见的功能,一些主要功能没有 需要自己开发
优点:
- 快速开发:通过拖拽式组件和可视化配置,快速搭建应用界面和逻辑。
- 集成能力:支持多种数据源和第三方服务的集成,扩展应用功能。
- 成本效益:减少编码工作量,降低开发成本,缩短应用上线时间。
缺点:
- 定制化能力有限:对于复杂和定制化的业务需求,可能无法完全满足。
- 学习曲线:开发者需熟悉平台特性和工具,有一定学习成本。
2、在Linux中以守护进程的方式运行jar包
使用nohup
命令可以让jar包以守护进程的方式运行
nohup java -jar your-application.jar &
nohup
:忽略挂起信号(SIGHUP),使得进程在终端关闭后能够继续运行。&
:将命令放入后台运行。
3、mybatisPlus乐观锁实现重试机制
MyBatis-Plus 提供了便捷的乐观锁支持,只需在实体类中添加版本号字段,在更新操作时会自动检查版本号。不过,MyBatis-Plus 本身并没有提供重试机制来处理乐观锁失败的情况。
下面是两种自定义的重试机制
- 在service层手动实现
(1)给mybatis plus拦截器添加乐观锁支持,用于对version字段进行操作
(2)在类中添加version属性,并添加@Version
注解
(3)在执行数据库更新操作时,通过定义一个 retryCount
属性来记录失败次数,并在更新失败时进行重试,直到达到最大重试次数(3次)。每次更新失败后,业务会休眠一定时间(100ms),如果最终仍未成功,则抛出业务异常。
- 使用AOP实现重试机制
- 使用
spring-retry
库实现重试机制
版本较新,可能与
spring-retry由于是基于AOP实现,在启动类上加@EnableRetry
后,只需要在需要的方法上添加@Retryable
注解即可实现重试机制。
Retryable注解重要的属性有:触发重试的异常、最大重试次数、重试间隔
在更新失败后抛出指定异常会触发重试机制
4、数据库多数据源支持
- 使用mybatis-plus配置多数据源
添加mybatis-plus和dynamic-datasource依赖
(1)在配置文件中添加多个数据源
(2)使用@DS("数据源")
注解切换数据源
- 使用sharding-jdbc管理多数据源
5、Java应用程序服务器有哪些
常见可以部署Java应用程序的服务器有:tomcat、jetty和jboss。
- Tomcat:开源的Servlet容器,主要用于执行Servlet和JSP页面。
- Jetty:开源的Servlet容器,基于netty实现,具有现代化、轻量级、高性能的优势
- Jboss:提供了企业级的解决方案,收费
spring boot内置的服务器为tomcat,通过移除tomcat依赖,导入Jetty依赖
移除依赖的标签<exclusions>
6、
mysql存储json
对象属性 <--> json数据
用户的地址信息,一般是拆分成单独的表,可以考虑在用户表中增加一个地址字段,用于存放地址的json数据
之前存放商品图片时使用,
分割,存放商品别名时也是使用,
分割,不是很合理(可以放入到集合中再序列化)
配置步骤:
- 自定义JSON序列化:通过继承
BaseTypeHandler
并实现序列化和反序列化逻辑,处理 JSON 数据的存储和读取。 - MyBatis-Plus 支持:利用 MyBatis-Plus 的字段类型处理器功能,简化 JSON 数据的处理。
- XML 映射配置:在 MyBatis 的 XML 映射文件中配置
resultMap
,并通过typeHandler
指定自定义的 JSON 类型处理器。
7、单点登录
单点登录(SSO)是一种身份验证机制,它允许用户在一个地方进行一次登录后,与之相关的服务就不用再进行登录。(登录一次,到处通行)
如在淘宝和天猫其中一个网站登录,另一个服务会自动登录
实现
1.在同域名下的实现
(1)将登录认证服务单独作为一个服务
(2)使用jwt实现session
-
为什么应用能拿到其它应用存放的jwt?
-
由于浏览器的安全机制(同源策略),相同域名的localStorage可以直接访问,不同域名之间的 localStorage 无法直接访问。所以在相同域名下应用能拿到其它应用存放的的jwt
2.不同域名下的实现
要解决的问题就是跨域怎么共享数据
-
基于Cookie的跨域SSOCookie共享:通过设置Cookie的Domain属性为一个父域名(例如.example.com),可以让子域名(如app1.example.com和app2.example.com)共享同一个会话Cookie。限制:这种方法仅适用于同一顶级域名下的子域名之间,对于完全不同的域名则不适用。
-
基于Token的跨域SSOOAuth 2.0/OpenID Connect:这是最常用的跨域SSO实现方式之一。用户在一个域内完成身份验证后,认证服务器会返回一个访问令牌(Access Token)。这个令牌可以被安全地传递到其他域,并用于验证用户的登录状态。
-
基于代理/网关的解决方案反向代理:使用反向代理服务器(如Nginx、Apache等)来转发请求并在后台处理身份验证逻辑,从而实现跨域SSO。API Gateway:利用API网关作为所有服务的入口点,集中处理身份验证和授权,然后再将请求转发到对应的服务。
3、单点登录控制(设备登录限制)
场景:假定一个账号只允许一个平板登录,一个手机登录,当再有平板或手机登陆时就把之前登录的顶掉
思路:我既然要控制不同设备登陆的数量,那在用户登陆的时候我肯定要知道是用什么设备登陆的,如何才能知道呢?这就需要前端给我传设备id,让我能知道这是什么设备,那问题就解决了
解决:使用redis的hash,大key存用户id,小key存token,value存设备id
实现:
-
前端在用户登录时要把设备Id一起带过来
-
验证账号密码正确后根据设备id让该顶掉的顶掉
-
遍历hash,找到手机1删除,将手机2加入即可
-
因为设备有被顶掉的风险,所以用户发送请求,我们在验证合法性时要加一步,我们可以拿到用户id和token,直接去redis里找,找不到设备就让他去重新登录
8、若依平台优缺点
前端采用Vue、Element UI;后端采用Spring Boot、Spring Security、Redis & Jwt。
优点
- 快速开发:Ruoyi 提供了一套完整的前、后端解决方案,可以快速搭建项目基础架构。
- 模块化设计:各个功能模块相对独立,便于维护和扩展。
- 社区支持:拥有活跃的社区支持,遇到问题可以较快得到帮助。
缺点
- 定制化限制:在某些特定业务场景下,需要较大的改动已有模块,可能会增加开发难度。
- 性能瓶颈:在高并发场景下,可能会出现性能瓶颈。
9、redis分布式锁(看门狗)
传统的分布式锁setNx
问题1:key的过期时间不好确定,过期了业务可能还没完成
问题2:如果key不设置过期时间,线程执行过程中断电后可能会造成死锁
Redisson锁:如果业务未执行完毕,会自动续命(ttl默认为30s,剩余3分之2的ttl时进行续命)
订单模块三重防重?(防止重复下单)
- 前端增加loading层
- 使用redis的setNx命令进行第二次防重(只能防住大部分的重复请求)
- 使用redisson进行第三次防重
(先使用redis。。不直接使用redisson是为了节省资源)
10、项目如何避免超卖
库存用redis作为缓存,后端用lua脚本,如果在此期间出现错误,用TCC分布式事务,不用seata的原因是并发性能低,它会启用我们的数据库,不适合高并发场景、
11、SWT是什么
在JVM(Java虚拟机)中,STW(Stop-The-World)事件是指在垃圾回收(Garbage Collection, GC)过程中,所有应用线程被暂停,以便GC线程可以安全地执行某些操作。
12、重写equals为什么要重写hashcode
两个对象在逻辑上相等,不仅需要equals方法返回true,而且需要hashcode方法返回相同的值
如果两个对象的 hashCode
方法返回相同的值,它们不一定相等,但相等的对象必须有相同的 hashCode
。
13、traceId全链路跟踪(前端后端)怎么实现的
前端pinia,traceId
前端axios请求拦截器,traceId
gateway traceId过滤器,从请求中获取traceId
下游服务traceId过滤器,放MDC
服务之间调用,openfegin拦截器,从MDC中拿traceId
Filebeat会将日志文件复制到es中进行日志分析,然后可以在Kibana中通过traceId搜索所有相关的日志信息
14、怎样解决跨域问题
使用@CrossOrigin注解:在资源上添加@CrossOrigin注解,设置单个资源的访问限制
@CrossOrigin(origins="*", allowedHeaders = "*"
//origins配置允许请求的源,allowedHeaders 配置允许的请求头
使用全局跨域配置:实现WebMvcConfigurer接口,重写addCorsMappings方法,在里面配置我们的跨域规则(比如允许的源,允许的请求头,允许的方法,以及是否允许携带cookie等验证),进行全局跨域配置
这里面OPTIONS请求方法的主要用途有两个:
1、获取服务器支持的HTTP请求方法;也是黑客经常使用的方法。
2、用来检查服务器的性能。例如:AJAX进行跨域请求时的预检,需要向另外一个域名的资源发送一个HTTP OPTIONS请求头,用以判断实际发送的请求是否安全。
使用CorsFilter跨域:实现filter接口,创建cros过滤器,设置响应头的配置
使用Nginx反向代理:设置响应头来支持跨域请求,并通过反向代理将请求转发到后端服务器
15、dockerfile文件里有什么
FROM registry.cn-beijing.aliyuncs.com/210app/210openjdk:8.2
WORKDIR /opt
COPY target/*.jar app.jar
EXPOSE 8080
#CMD ["java", "-jar", "app.jar"]
CMD java ${JAVA_TOOL_OPTIONS} -jar app.jar
16、重定向和转发区别
1> 重定向 2 次请求,转发 1 次请求
2> 重定向地址栏会变,转发地址栏不变
3> 重定向是浏览器跳转,请求转发是服务器跳转
4> 重定向可以跳转到任意网址,请求转发只能跳转当前项目
5>重定向会丢失请求参数, 请求转发不会丢失请求数据
17、为什么使用 Base64 做通用上传?
-
对于前端无论什么格式文件都可以转 Base64 通过post请求传给后端
-
服务器端不需要处理复杂的多部分表单解析,可以更直接地读取和处理Base64编码的数据
-
不用引入额外的依赖
18、nginx如何处理请求
19、懒汉式的DCL双重检查锁
第一重防止一个进程快,一个进程慢,而快的进程创建完对象就不让慢的对象获取锁了,防止重复创建对象
第二重防止并发条件下重复创建对象,也是只能创建一个对象
private volatile static Singleton instance;
volatile关键字保证多线程下线程的可见性但不保证原子性
20、mybatis对应接口的底层原理
MyBatis 使用动态代理技术为 Mapper 接口生成代理对象,拦截方法调用,根据方法名和参数映射到对应的 SQL 语句执行,并返回结果。
通过 AOP 可以在方法调用前后添加额外的逻辑,如事务管理和日志记录
21、springboot自动装载原理详细版
1.@SpringBootApplication是一个组合注解,包含了@SpringBootConfiguration(Spring装配类)、@EnableAutoConfiguration(启动自动配置)和@ComponentScan(扫描基础包和自包,用于组件扫描)
2.当@EnableAutoConfiguration 被使用时,它实际上导入了AutoConfigurationImportSelector (ImportSelector)类,里面的 selectImports方法用于选择要导入的自动配置类列表
3 .AutoConfigurationImportSelector | 里的 getCandidateConfigurations中SpringFactoriesLoader类 使用SPi技术 | 会根据 SpringFactoriesLoader.loadFactoryNames 扫描 META-INF/spring.factories中的全类名,再根据某些条件将Bean放到IOC中。
一般会根据@Conditional条件注解的变体来决定哪些配置类应该被激活
22、dubbo和springcloudalibaba的区别
1、支持的协议:dubbo主要用tcp协议,springcloud主要支持http协议
2、服务治理不同:dubbo将接口注册到zookeeper实现服务治理,而springcloud是注册到nacos
3、性能高低:dubbo性能高,springcloud性能略低
4、dubbo使用的Java语言而springcloudalibaba支持多种语言
5、dubbo返回的是一个json数据,而springcloud返回的是一个http响应
23、数据库undolog、redolog和seta分布式事务的undolog(seta没有redolog)区别
数据库:undolog记录了数据修改前的数据,方便事务回滚
redolog记录了数据修改的操作,方便我们将数据持久化到磁盘上
seta:undolog记录了分支事务的修改操作,方便回滚事务,如果事务执行成功我们就删除UN对哦咯个1,失败我们就根据undolog表里的数据进行回滚,注意每个短事务都有自己的undolog表,事务回滚是所有短事务都要回滚
binlog是数据库的一张表:
- Query Event:记录 SQL 语句的执行,包括 DDL(数据定义语言)和 DML(数据操作语言)语句。
- Table Map Event:记录表的元数据信息,用于后续的行记录事件。
- Write Rows Event:记录插入操作。
- Update Rows Event:记录更新操作。
- Delete Rows Event:记录删除操作。
- Xid Event:记录事务的提交。
24、序列化和反序列化,以及什么时候序列化和反序列化
序列化:是将对象转换为字节流
反序列化:将字节流转换为对象
什么时候序列化:
- 网络传输:在网络应用中,对象需要通过网络传输到其他系统或服务。序列化可以将对象转换为字节流,便于在网络中传输。
- 持久化:将对象的状态保存到磁盘上,以便后续可以恢复。例如,将用户会话信息保存到文件或数据库中。
- 对象克隆:通过序列化和反序列化可以实现深克隆,即创建一个与原对象完全独立的新对象。
什么时候反序列化:
- 网络接收:在网络应用中,接收到的字节流需要转换回对象,以便进一步处理。
- 持久化恢复:从磁盘上读取对象的状态,恢复到内存中。
- 对象克隆:通过反序列化可以恢复一个与原对象完全独立的新对象。
25、spring注入bean的方式
XML配置
<bean id="userService" class="com.example.service.UserServiceImpl">
<property name="userRepository" ref="userRepository"/>
</bean>
<bean id="userRepository" class="com.example.repository.UserRepositoryImpl"/>
注解配置(@Autowired
注解、@Resource
注解)
@Autowired
注解
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
@Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 其他方法
}
@Resource
注解:
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserRepository userRepository;
// 其他方法
}
Java配置:
@Configuration
和 @Bean
注解
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserServiceImpl(userRepository());
}
@Bean
public UserRepository userRepository() {
return new UserRepositoryImpl();
}
}
26、怎么进入线程阻塞状态
两种方式:join、上锁
join和yield方法的区别
join:join
方法允许一个线程等待另一个线程完成。调用 join
方法的线程会进入阻塞状态,直到被调用的线程执行完毕
yield:yield
方法允许当前线程让出CPU资源,给其他线程执行的机会,但是它释放资源后也会进入枪锁,可能会再次抢到锁。
27、Java线程安全的集合有哪些
Vector:
类似于 ArrayList
,但所有方法都是同步的,因此是线程安全的
Stack:
继承自 Vector
,提供了栈操作(如 push
和 pop
),因此也是线程安全的
Hashtable:
ConcurrentHashMap:
28、前端项目基于什么发布,为什么不基于tomcat
前端项目基于nginx发布,因为前端项目实际上就是静态页面,属于静态资源,而nginx可以作为静态资源服务器,tomcat主要是发布jar包的项目,主要用于后端项目发布
29、类加载器工作原理
类加载过程可以分为三个主要阶段:加载(Loading)、链接(Linking)和初始化(Initialization)
加载:读取字节码文件、生成类对象、存储类对象
链接:链接又分为验证、准备、解析三个阶段
验证:检查字节码文件格式、检查元数据信息、检查字节码指令是否和规范
准备:为静态变量分配内存
解析:符号引用转为直接引用
初始化:初始化我们的静态资源,如静态类,静态代码块
30、EasyES
31、nginx如何处理一个请求的?
首先,nginx 在启动时,会解析配置文件,得到需要监听的端口80与ip 地址,然后在nginx 的master 进程里面先初始化好这个监控的 socket,再进行 listen,然后再 fork 出多个子进程出来子进程会竞争 accept 新的连接。
此时,客户端就可以向 nginx 发起连接了。当客户端与 nginx 进行三次握手,与nginx 建立好一个连接后,此时,某一个子进程会 accept 成功,然后创建 nqinx 对连接的封装,即ngx_connectiont结构体,接着,根据事件调用相应的事件处理模块,如 http 模块与客户端进行数据的交换。
最后,nginx 或客户端来主动关掉连接,到此,一个连接就寿终正寝了
32、为什么选择 HttpClient 而不是HttpURLConnection
1. HttpClient 提供了更高级的 API,让代码更加简洁HttpURLConnection 较为底层,需要手动处理细节
2.HttpClient 有内置连接池,适合高并发场景HttpURLConnection 每次请求需要新建链接
3. HttpClient 需要引入额外的库HttpURLConnection是 Java 标准库的一部分,不需要音容额外的库Nginx是如何处理一个请求的编辑大纲
33、Nginx 为什么性能高
C语言编写
采用异步非阻塞,InPoll模型,支持高并发
一个主进程,多个工作进程,主进程主要负责分发请求交给工作进程完成
34、OpenfeignDecoder (openfeign解码器)原理
1.实现 Decoker 接口,重写 decode 方法
2.对 decode 方法参数 response 进行判断是否为空,不为空转换成 Json 类型
3.判断 Json 类型中的 code 是否为 0,不为 0 抛出异常
4.将 Json 的 data 转换成 string 类型,获取 data 的全路径名,并判断 data 的 type 类型,并创建一个空 object 对象
5.如果 data 类型是 List 类型进行手动转换,非 list 判断是不是 Java 自带类型(ava.lang 包下的),是 Java 自带类型就直接获取数据,非 Java 类型就根据获得 data的类型进行转换成 Bean 对象
35、如何保证接口幂等性 (===========)
36、DTO、VO、PO都是什么
DTO 通常用于将数据从数据访问层(DAO)传递到业务逻辑层(Service),再从业务逻辑层传递到表示层(Controller)
dto:前后端交互传递的实体对象
vo:我们传递给前端的视图对象
po:与数据库交互的对象
37、FactoryBean和BeanFactory
38、bean实例化和初始化的区别
39、百万数据添加字段
新建一个副表,加入新加的字段
找到原表最大时间戳,将最大时间戳的数据全量同步到副表里
修改副表名为原表名
接下来增量同步原表最大时间戳之后的数据到新表里
40、mybatis和JDBC区别
1、mybatis简化代码
2、mybatis把SQL语句与代码解耦
3、xml文件自动映射
4、mybatis有连接池,可以提高效率,JDBC没有
5、动态SQL
41、黑名单hash结构大key存的啥,小key存的啥
大key就是黑名单这个标识
小key存的商品id
value可以存时间戳或者商品信息,存时间戳的意义就是可以查看这个商品什么时候加黑名单的
42、pinia和localstorage
pinia是管理数据存放在哪的,如LocalStorage ,cookie
LocalStorage 是持久化存放数据的
43、Java怎么实现动态代理
44、慢接口怎么追踪的
skywalking
45、nginx的配置文件
46、seata分布式事务
先说一下TC、TM、RM
在 Seata 的架构中,一共有三个角色:
TC (Transaction Coordinator) - 事务协调者(带头大哥)
维护全局和分支事务的状态,驱动全局事务提交或回滚。
TM (Transaction Manager) - 事务管理器 (鸡妈妈)
定义全局事务的范围:开始全局事务、提交或回滚全局事务。
RM (Resource Manager) - 资源管理器
管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。
其中,TC 为单独部署的 Server 服务端,TM 和 RM 为嵌入到应用中的 Client 客户端。
1、TM请求TC开启一个全局事务,TC生成一个XID(长事务ID),XID在微服务调用链路中传递
2、RM请求TC把本地事务注册为全局事物的分支事务(短事务)并传递XID(长事务ID)
3、TM根据RM返回的状态向TC发送提交或回滚请求(短事务是先执行了,不会等待TC的通知再去执行)
4、TC驱动RM对自己本地事务进行提交或者回滚,执行成功就在提交完成后删除undolog,失败就在回滚以后删除undolog
47、装箱、拆箱
装箱 是将基本数据类型转换为对应的包装类对象的过程。例如,将 int
类型的值转换为 Integer
对象。
拆箱 是将包装类对象转换为对应的基本数据类型的过程。例如,将 Integer
对象转换为 int
类型的值
为什么要装箱:
1.泛型的支持:泛型机制要求类型参数必须是引用类型,因此在使用泛型时,基本数据类型需要装箱为对应的包装类
2.集合类的支持:Java 的集合类(如 List
, Set
, Map
等)只能存储对象,不能直接存储基本数据类型。因此,使用包装类可以将基本数据类型转换为对象,从而可以存储在集合中。
3.缓存机制:Integer
类在 -128
到 127
之间的值会进行缓存,多次装箱相同的值会返回同一个对象。对于超出这个范围的值,每次装箱都会创建新的对象。
4.空值支持:基本数据类型不能表示空值,而包装类可以为 null
48、Java中变量、常量,静态变量、非静态变量的区别
- 变量:用于存储数据的标识符,可以是基本类型或引用类型。
- 常量:使用
final
关键字声明,值在程序运行过程中不会改变。 - 静态变量:属于类,所有对象共享同一个副本,可以通过类名或对象访问。
- 非静态变量:属于类的实例,每个对象有自己的独立副本,只能通过对象访问。
49、integer的缓存机制
把-128到+127放入缓存中;好处是提高这些常用的数据的复用性,他们放在元空间里,是共享的
比如integer a = 127与 integer b = 127他俩是一个,因为都是从元空间里拿的数据;但是integer a = 128与 integer b = 128他俩不一样,超过了127,是新建的两个对象;
50、spring优势其实就是springaop和ioc
51、如何实现线程同步
synchronized
关键字:是最常用的线程同步机制之一。它可以用于方法或代码块,确保同一时间只有一个线程可以执行同步代码。
ReentrantLock
:是 java.util.concurrent.locks
包中的一个可重入锁,提供了比 synchronized
更灵活的锁控制
Atomic
类:提供原子操作,适用于简单的同步需求
wait方法
join方法
52、什么时候不要使用索引?
数据库和表的数据比较少的时候,不需要,因为他还是会全表查询
53、解释什么是skywalking以及它的重要性
skywalking是一个开源的分布式追踪与性能监视平台,特别适用于微服务架构、云原生环境以及基于容器(如Docker、Kubernetes)的应用部署
54、springboot和springcloud的区别
spring boot 一般适用于单体架构,调试简单,耦合度高
spring cloud 适用于分布式架构,实现了解耦,做到了更细粒度的划分,做到了单一职责
55、什么是降级、熔断、为什么要降级、熔断
熔断:开 关 半开半关
熔断:熔断就是有一个阈值,向服务发起请求后,如果不成功,就会记录次数,然后当连续失败次数达到阈值时,下次请求的时候就会直接把这个服务停止。请求有三种状态,可以请求(开),不可请求(关),还有一个中间状态,相当于半开状态,半开状态是什么意思呢,就是可以尝试着去请求,就可以在关闭状态后一段时间,发一个请求尝试一下是否可以请求成功,如果不成功,继续保持关闭状态,如果请求成功,则变成开放状态。
降级:降级其实就相当于,当我们向一个服务发起请求,当请求超时了,就会把这次请求记录到服务中,然后就会尝试向其他服务发请求,如果还没成功,就对这次请求进行处理(怎么处理取决于业务需求如)就相当于try catch一样的逻辑,当然Sentinel底层使用aop来实现的
为什么:是为了保护我们下游的服务,避免服务被打垮
56、限流与降级区别
1.目标不同:
限流是为了避免系统过载,保护系统资源;
降级是为了在服务出现异常时避免整个系统受到影响。
2.触发条件不同:
限流通常是基于流量大小或频率来触发;
降级则是基于服务的健康状态或异常情况来触发。
3.行为不同:
限流可能会拒绝部分请求;
降级则是对异常服务的替代处理,返回预定义的结果或错误信息。
57、接口中的方法
接口中可以写抽象方法、默认方法、静态方法以及私有方法。
抽象方法:抽象方法是没有方法体的方法,只有方法签名。实现接口的类必须提供这些抽象方法的具体实现;并且接口可以写任意数量的抽象方法
默认方法:默认方法是在接口中提供默认实现的方法。实现接口的类可以选择性地覆盖这些默认方法,同样可以有任意数量的默认方法
静态方法:静态方法是在接口中定义的静态方法,不能被实现类继承,只能通过接口调用。
私有方法:私有方法是从 Java 9 开始引入的,用于在接口中提供辅助方法,这些方法只能在接口内部使用
public interface MyInterface {
void method1(); // 抽象方法
default void method2() {
System.out.println("Default implementation of method2");
helperMethod();
}
static void method3() {
System.out.println("Static implementation of method3");
helperMethod();
}
private void helperMethod() {
System.out.println("This is a private helper method");
}
}
58、如何优化SQL
-
加索引
-
避免常见的索引不生效场景
-
避免返回不必要的数据:意思是要什么查什么,不需要过多查询不需要的数据;另外查询SQL尽量不要使用select *,而是select具体字段
-
减少不必要的逻辑:如果明确检索结果中不会有重复的记录,推荐union all 替换 union
-
分批量进行思想:批量插入性能好,更加省时间
-
读写分离:主库主要负责写,和一些实时性比较高的读。而从库就负责读实时性要求不高的请求。
-
优化sql结构
-
分库分表
-
性能优化分析神器—explain
-
慢SQL排查思路
59、union和union all的区别
UNION
:合并结果集并去除重复记录。适用于需要唯一记录的场景,但可能会有性能开销。
UNION ALL
:合并结果集并保留所有记录,包括重复记录。适用于不需要去除重复记录的场景,性能较好