1. idea在debug的时候,怎么看当前有没有事务存在?
在你关心的业务方法或事务边界处打断点,然后在调试器的“Evaluate Expression”窗口中输入:
org.springframework.transaction.support.TransactionSynchronizationManager.isActualTransactionActive()
如果返回 true,说明当前线程有一个活动事务。
2. Spring中factoryBean有何作用?
- FactoryBean 是一个工厂模式的接口,可以动态创建 Bean,而不是直接将 FactoryBean 本身注册到容器。
- 使用 &beanName 可以获取 FactoryBean 本身,而不是 getObject() 生成的 Bean。
- 适用于创建复杂对象、代理对象、动态实例化等场景。
3. 我们现在都不用配置文件了,Springboot注入都是用注解,请问注解还能用Factorybean吗?为什么感觉开发中没用到过Factorybean
是的,在 Spring Boot 中仍然可以使用 FactoryBean,但由于 Spring Boot 提供了更优雅的方式(比如 @Bean、@Component、@ConfigurationProperties 等),绝大多数开发场景下不再需要手动实现 FactoryBean,这就是你感觉在实际开发中很少见到 FactoryBean 的原因。不过,在某些特殊场景下,比如创建代理对象、动态生成复杂 Bean 时,FactoryBean 仍然有其价值。
- Spring Boot 中仍然可以用 FactoryBean,但一般不需要,@Bean 和 @Component 足够应对大多数场景。
- FactoryBean 适用于创建 代理对象、动态实例化复杂 Bean、第三方框架集成 等场景。
- 如果你的业务代码中很少涉及动态代理、复杂初始化或框架开发,那几乎不会遇到 FactoryBean。
- 除非你在框架级开发或需要动态生成 Bean,否则 FactoryBean 不是日常开发中的首选方式。
4. 事件嵌套问题
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) 嵌套
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT),第二个事件会发不出去,这是为何?
因为TMD资源释放发生在finally中,第二个方法执行的时候第一个还没有释放事务资源。第二个其实是带着事务进去的,带着事务不会挂起当前事务也不会开启新事务,所以导致AFTER_COMMIT无法生效。想要生效,第二个需要设置传播行为为REQUIRES_NEW。
5. 在事务执行过程中,有没有事务id或者名字什么的,好让我在代码执行的时候观察到此线程上的事务是否发生改变。
事务名称,也可以debug的时候执行。
@Transactional
public void myMethod() {
String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
System.out.println("Current transaction name: " + transactionName);
}
6. startTransaction 和 prepareTransactionStatus有何区别?创建的事务一样吗?
startTransaction(definition, transaction, false, debugEnabled, suspendedResources);
prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
1. startTransaction 方法主要功能:
startTransaction 负责启动一个新事务,或根据事务传播行为在现有事务中启动一个新事务。它主要用于创建和管理事务的生命周期,特别是涉及到事务的开始、挂起和恢复。
- 事务传播行为:startTransaction 方法通常在 PROPAGATION_REQUIRES_NEW 或类似需要新事务的场景中调用。在这些情况下,它可能会挂起当前事务并启动一个新的事务。
- 挂起资源:该方法的参数 suspendedResources 是当前挂起事务的资源,主要用于处理需要挂起当前事务的情况(如 PROPAGATION_REQUIRES_NEW)。如果有挂起的资源,新的事务会在这些资源的基础上启动。
工作流程:
- 如果当前事务传播行为要求新事务(如 PROPAGATION_REQUIRES_NEW),它会挂起现有事务并启动一个新的事务。
- 该方法会处理事务的开始,并可能涉及挂起现有事务资源的管理。
- 返回一个新的 TransactionStatus,代表正在进行的事务状态。
2. prepareTransactionStatus 方法主要功能:
prepareTransactionStatus 主要用于准备和创建一个新的事务状态,但它不负责启动新事务。它通常用于处理已经存在的事务,或者在特定的传播行为下(如 PROPAGATION_REQUIRED)参与现有事务。
- 事务同步:prepareTransactionStatus 会初始化事务同步支持(通过 prepareSynchronization 方法),确保事务在当前线程上进行适当的同步操作。
- 返回事务状态:它返回的是一个 TransactionStatus,这个状态代表当前事务的同步和状态,但并不一定启动一个新的事务。
工作流程:
- 它首先调用 newTransactionStatus 来创建一个新的事务状态。
- 然后,它通过 prepareSynchronization 初始化事务同步,确保事务状态可以正确同步到当前线程。
- 返回的 TransactionStatus 通常用于表示事务的状态和同步信息,而不会立即启动一个新的事务。
3. 关键区别
特性
startTransaction
prepareTransactionStatus
事务创建/启动
负责启动一个新的事务或在现有事务中启动新事务
不直接启动新事务,主要用于准备事务状态
挂起现有事务
可能会挂起当前事务并启动新事务(例如
PROPAGATION_REQUIRES_NEW)
不涉及挂起现有事务,只是在现有事务中参与或创建事务状态
事务同步
启动新事务时会处理同步操作(如需要)
初始化事务同步,确保事务能够在当前线程同步
事务状态返回
返回一个新的 TransactionStatus,代表新启动的事务
返回一个新的 TransactionStatus,表示事务的状态和同步信息
适用场景
通常用于 PROPAGATION_REQUIRES_NEW或事务的实际开始
用于在现有事务中创建或参与事务状态
- startTransaction 是实际启动事务的地方,通常用于需要创建新事务的场景。
- prepareTransactionStatus 是事务状态的准备工作,更多的是在现有事务中准备和管理同步,确保事务能正确地同步到当前线程。
7. Elasticsearch中refresh_interval(索引刷新频率)
刷新(Refresh) 是将内存中的 Lucene 索引数据(In-memory buffer)转换为可搜索的段(Segment)的过程。
写入 Elasticsearch 的数据会先暂存在内存缓冲区,只有经过 Refresh 后,这些数据才能被搜索到。
默认是1s刷新一次,调整这个参数可以优化写入性能或实时搜索性能。想写入快,就设置为-1,表示禁用刷新,或者设置30s,表示30s刷一次;想提升搜索的实时性,就设置的小一点,例如1s。
refresh_interval这个是动态参数,修改后立即生效。所以可以手动触发。
8. Lucene和Es
Lucene 是 Elasticsearch 的底层搜索引擎库,负责数据的存储和检索。其核心机制如下:
Lucene 类似汽车的发动机,Elasticsearch 则是一辆完整的汽车,整合了发动机(Lucene)、底盘(分布式架构)、方向盘(API)。
Segment特性:
9. vmware网络连接
需要对外服务或真实网络测试用桥接,便捷上网或隔离环境用NAT,不上外网用仅主机。
桥接模式(Bridged Mode)
- 虚拟机直接连接到宿主机的物理网络适配器,相当于在物理网络中新增一个独立设备。
- 虚拟机和宿主机处于同一局域网,共享同一网段(如宿主机IP为 192.168.1.100,虚拟机可能为 192.168.1.101)。
- 暴露虚拟机到物理网络,可能面临外部攻击或网络策略限制。
NAT模式(Network Address Translation)
- 虚拟机通过VMware创建的虚拟网络(如 192.168.122.0/24)连接,宿主机作为虚拟网络的网关和NAT设备。
- 虚拟机与宿主机处于不同子网,通过宿主机的IP地址访问外网。
- 天然隔离,虚拟机隐藏于宿主机后,安全性更高。
仅主机模式
- 虚拟机仅能与宿主机通信,无法直接访问外部网络(如互联网或局域网)。
- 宿主机与虚拟机之间通过VMware创建的虚拟私有网络连接,形成一个完全封闭的环境。
- 仅主机模式是最封闭的网络模式,适合需要完全隔离的场景。
10. Spark和Hadoop MapReduce有什么异同,各自有哪些优势?
想象你有一仓库的图书(数据),需要快速完成以下任务:
传统单机软件(如Excel)无法处理这种规模的问题,而核心框架就是为解决这些问题而生的工具箱。
特性
Hadoop MapReduce
Spark
数据处理模型
基于磁盘的批处理
基于内存的批处理 + 流处理 + 交互式查询
执行引擎
分阶段(Map → Shuffle → Reduce)
基于DAG(有向无环图)优化任务执行流程
延迟
高延迟(分钟级)
低延迟(亚秒级,微批处理)
API灵活性
需编写大量底层代码(Java/Python)
高级API(Scala/Java/Python/R),支持SQL和DSL
迭代计算效率
每次迭代需读写磁盘,效率低
内存缓存中间结果,适合迭代算法(如机器学习)
生态扩展
依赖Hive、Pig等工具扩展功能
内置Spark SQL、MLlib、GraphX、Structured Streaming等库
Hadoop MapReduce的优势
- 成熟稳定:适合超大规模数据批处理,尤其对延迟不敏感的任务(如ETL)。
- 容错简单:通过磁盘持久化实现容错,适合硬件故障频繁的环境。
- 资源要求低:内存消耗较少,适合资源受限的场景。
- 与HDFS深度集成:本地化计算优化减少数据移动开销。
典型场景:日志分析、历史数据归档、离线报表生成。
Spark的优势
- 速度优势:内存计算比MapReduce快10~100倍(如迭代算法)。
- 统一引擎:支持批处理、流处理、机器学习、图计算等多种任务。
- 开发效率高:简洁的API和丰富的库(如DataFrame API、PySpark)。
- 实时处理:Structured Streaming支持准实时数据流处理。
- 优化器:Catalyst查询优化器自动优化执行计划。
典型场景:实时推荐系统、交互式数据探索、机器学习流水线、复杂DAG任务。
11. 数据湖是什么?为什么需要数据湖,其解决了哪些问题
数据湖(Data Lake)是一种集中式存储架构,用于存储企业所有原始格式(结构化、半结构化、非结构化)的海量数据,并支持按需处理和分析。它像“自然湖泊”一样容纳各种来源的“数据流水”,无需预先定义数据结构或用途,为后续灵活分析提供基础。
- 数据仓库像“瓶装水工厂”:数据需过滤、消毒、封装后才能饮用(使用)。
- 数据湖像“天然湖泊”:数据以原始形态存储,可按需取用(直接饮用、煮沸或加工成饮料)。
12. java nio中selector是什么?可以解决什么问题?
在传统的阻塞 I/O 中,每一个客户端连接通常都需要一个单独的线程来处理。而使用 Selector,一个线程就能够同时管理多个通道的 I/O 操作,从而大幅减少线程数量。对于高并发场景,能够极大提高系统的效率和资源利用率。
Selector 的工作流程通常如下:
-
注册通道:首先,将一个或多个 Channel 注册到 Selector 上。每个通道在注册时可以指定感兴趣的事件类型,例如 OP_READ(读取事件)、OP_WRITE(写入事件)、OP_CONNECT(连接事件)等。
selector = Selector.open(); channel.configureBlocking(false); // 设置为非阻塞模式 channel.register(selector, SelectionKey.OP_READ); // 注册读取事件
-
事件轮询:Selector 会不断轮询已注册的通道,检查哪些通道有感兴趣的事件发生。当一个或多个通道的事件发生时,Selector 会返回相应的 SelectionKey,用于标识哪个通道已经准备好进行 I/O 操作。
while (true) { int readyChannels = selector.select(); // 阻塞直到有事件发生 if (readyChannels == 0) continue;
// 处理已就绪的通道 Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); keyIterator.remove(); // 处理就绪的通道(例如读取数据) }}
-
处理事件:当 Selector 检测到某个通道有事件发生时,程序就可以对这些通道进行处理。例如,如果一个通道有数据可读,程序就可以读取数据;如果某个通道可写,程序就可以写数据。
13. java nio中selector工作原理最适合哪种io模型?
Selector 允许单线程管理多个通道(Channel)的 I/O 操作,支持非阻塞模式。在非阻塞模式下,线程可以轮询多个通道,检查它们是否准备好进行读取或写入,而不需要阻塞等待操作完成。这样可以有效提升资源利用率,尤其在处理大量并发连接时。
14. 永远不要对公共分支或已被他人拉取的分支执行 rebase。
15. 我有一张mysql表,其中有个时间字段,bigint类型的,存的是时间戳。现在准备按照日期分组,怎么写sql?
就是这么简单,我竟然一度以为没法实现,或者说需要我自己写很复杂的sql实现。
-
timestamp_column / 1000:时间戳单位降级(毫秒→秒)
-
FROM_UNIXTIME():将秒级Unix时间戳转为YYYY-MM-DD hh:mm:ss格式
SELECT DATE(FROM_UNIXTIME(timestamp_column / 1000)) AS date_group, COUNT(*) AS total FROM your_table GROUP BY date_group ORDER BY date_group;
16. mysql直接使用datetime和用bigint存储时间戳,哪个好?
能力维度
BIGINT时间戳
DATETIME
时区支持
✅ 隐式存储UTC时间,需显式转换时区
❌ 无时区信息,存储字面时间(如2023-01-01 08:00:00)
时间精度
✅ 可自由定义(秒、毫秒、微秒)
✅ 最高支持微秒(如DATETIME(6))
日期运算
❌ 需用数学计算(如加减秒数)
✅ 原生支持(如DATE_ADD、INTERVAL)
日期函数
❌ 需先转日期类型(FROM_UNIXTIME)
✅ 直接使用(如DAY()、MONTH())
可读性
❌ 需转换才能理解
✅ 直接可读(如2023-01-01)
跨数据库兼容性
✅ 统一用整数存储
❌ 类型实现可能不同(如Oracle的DATE)
BIGINT时间戳 更适合需要 多时区、高精度时间、跨系统兼容 的场景。
DATETIME 更适合 单一时区、高频日期操作、开发友好性优先 的场景。
总之,尽量用时间戳。
17. java Queue LinkedList
Queue(队列)接口定义了一组操作,用于实现 先进先出(FIFO) 的数据结构,LinkedList实现了Queue接口,所以可以把LinkedList作为队列来使用。
Queue 接口的核心方法
方法
行为
成功时返回值
失败时行为
boolean add(E e)
将元素插入队列尾部
true
队列已满 → 抛出IllegalStateException
boolean offer(E e)
将元素插入队列尾部(推荐使用)
true(成功)
队列已满 → 返回false
E remove()
移除并返回队列头部的元素
被移除的元素
队列为空 → 抛出NoSuchElementException
E poll()
移除并返回队列头部的元素(推荐使用)
被移除的元素
队列为空 → 返回null
E element()
返回队列头部的元素(不删除)
队列头部的元素
队列为空 → 抛出NoSuchElementException
E peek()
返回队列头部的元素(不删除,推荐使用)
队列头部的元素
队列为空 → 返回null
18. MyBatis是如何将SQL执行结果映射到Java对象的?
MyBatis 将 SQL 执行结果映射到 Java 对象的过程主要通过以下几个步骤:
19 Consul
Consul 是一个由 HashiCorp 开发的开源工具,用于服务发现、配置管理和分布式系统的健康检查。它旨在简化微服务架构中的服务管理,特别是在动态环境中,支持服务之间的自动发现和通信。
20. SPEL
SPEL(Spring Expression Language)是 Spring 的表达式语言,允许在 Spring 配置文件、注解以及其他地方通过简洁的表达式动态地计算值。类似于脚本语言,支持计算、条件判断、对象访问、数组操作等。
@Value("#{2 * 3}") // 计算表达式的结果 2 * 3
private int result;
@Value("#{person.getName()}") // 调用 person bean 的 getName 方法
private String personNameFromMethod;
@Value("#{T(java.util.Arrays).asList('apple', 'banana', 'cherry')}") // 创建一个 List
private List<String> fruits;
@Value("#{fruits[0]}") // 访问 fruits 列表中的第一个元素
private String firstFruit;
21. micrometer + Prometheus + grafana
通过micrometer将数据暴露出去,给到Prometheus,然后用grafana展示数据,一套完整的监控。
22. T95和T99
T95 (95th percentile):表示数据集中有 95% 的数据点在该值以下,只有 5% 的数据点在该值以上。也就是说,T95 是数据集中的一个位置,超过这个值的 5% 的数据代表了最极端的部分。
T99 (99th percentile):表示数据集中有 99% 的数据点在该值以下,只有 1% 的数据点在该值以上。T99 是一个更高的百分位值,表示只有 1% 的数据点超出了这个值。
它们可以帮助开发者评估系统的响应时间分布,识别性能瓶颈,并优化系统以改善用户体验。
23. 接口的版本管理
在Controller中写相同的请求路径,然后加个自定义注解标记版本,这么做很好,避免了在接口前加V12345,还可以定义选择版本的策略。但是你需要继承RequestMappingHandlerMapping,自定义请求映射行为,这样才可以有相同的路径,然后根据注解选择合适的版本。
24. Jakarta EE(前身为 Java EE),为啥不接着叫java ee
Java EE 最初是由 Sun Microsystems 开发的,后来 Sun 被 Oracle 收购。随着时间的推移,Oracle 拥有了 Java 的商标和版权。由于 Oracle 对 Java EE 的控制,社区对其发展和管理的灵活性受到了一定限制。
因此,Jakarta EE 的更名是出于商标和版权的考虑,同时也是为了促进更开放的开发模式和社区参与。这个新名称代表了一个新的起点,旨在继续推动企业级 Java 应用程序的开发和创新。
25. spring boot 3.4.3 jetbrains.annotations.Nullable无了
import org.jetbrains.annotations.Nullable;
这个在spring boot3.2.4中还存在,到3.4.3中就没了
Spring Boot 3.2.x:可能在旧版本中通过间接依赖(如 Lombok 或其他第三方库)引入了 JetBrains 注解库,导致该注解可用。
Spring Boot 3.4.3:新版本调整了默认依赖管理,可能移除或更新了间接依赖,导致 JetBrains 注解库不再被自动引入
26. ES 单独指定对某个字段是否索引
PUT /my_index
{
"mappings": {
"properties": {
"views": {
"type": "integer", // 整数类型
"index": false // 不索引,无法搜索
}
}
}
}
27. 怎么定位慢sql?
启用慢查询日志
MySQL 提供了慢查询日志功能,可以记录执行时间超过指定阈值的查询。在 MySQL 配置文件(通常是 my.cnf 或 my.ini)中添加或修改以下配置。然后使用 EXPLAIN 分析查询
[mysqld]
slow_query_log = ON
slow_query_log_file = D:/mysql/mysql-8.0.22-winx64/logs/slow-query.log
# 记录执行时间超过 1 秒的查询
long_query_time = 1