印宏网络科技 Java开发 一面 面经
1. 自我介绍
您好,我是XXX,目前就读于XX大学计算机科学与技术专业,大三/大四学生。我的技术方向是Java后端开发,有扎实的编程基础和项目经验。
在技术栈方面,我熟练掌握Java语言和面向对象编程思想,熟悉Spring、Spring Boot、MyBatis等主流框架。数据库方面熟悉MySQL的使用和优化,了解Redis缓存的应用。对分布式系统、微服务架构有一定了解。
项目经验方面,我做过在线教育平台、即时通讯系统等项目。在即时通讯项目中,我负责实现了基于WebSocket的实时聊天功能,包括单聊、群聊、消息推送等模块。通过这个项目,我深入学习了WebSocket协议、Netty框架,以及高并发场景下的系统设计。
我的学习能力比较强,遇到问题会主动查资料、看源码、做实验来解决。平时会关注技术社区,学习新技术和最佳实践。我对技术充满热情,希望能在实际工作中不断提升自己,为团队创造价值。
2. Redis的持久化机制,RDB和AOF的区别
Redis持久化的必要性:
Redis是内存数据库,数据存储在内存中,如果服务器宕机或重启,数据就会丢失。持久化机制可以把内存中的数据保存到磁盘,重启后恢复数据,保证数据安全。
RDB持久化:
RDB是快照方式,在某个时间点把内存中的所有数据生成快照保存到磁盘。可以手动执行save或bgsave命令,也可以配置自动触发条件,比如900秒内有1个key变化就触发。
RDB的实现是fork一个子进程,子进程把数据写入临时文件,写完后替换旧的RDB文件。这个过程不会阻塞主进程,主进程可以继续处理请求。
RDB的优点是文件紧凑,适合备份和灾难恢复。恢复速度快,因为直接加载数据到内存。对性能影响小,因为是子进程操作。
RDB的缺点是可能丢失数据。如果Redis在两次快照之间宕机,这期间的数据就会丢失。而且fork子进程需要时间,数据量大时可能影响性能。
AOF持久化:
AOF是追加日志方式,记录每个写操作命令到文件末尾。Redis重启时重新执行这些命令恢复数据。
AOF有三种同步策略。always是每个命令都同步到磁盘,最安全但最慢。everysec是每秒同步一次,这是推荐的方式,最多丢失1秒数据。no是由操作系统决定何时同步,最快但最不安全。
AOF文件会越来越大,Redis提供了重写机制。重写时会根据内存中的数据生成新的AOF文件,只保留恢复数据所需的最少命令。比如对同一个key的多次set操作,重写后只保留最后一次。
AOF的优点是数据更安全,最多丢失1秒数据。文件可读,可以手动修复。
AOF的缺点是文件体积大,恢复速度慢。对性能影响大,因为要频繁写磁盘。
混合持久化:
Redis 4.0后支持混合持久化,结合了RDB和AOF的优点。AOF重写时,前半部分用RDB格式保存数据快照,后半部分用AOF格式记录增量命令。这样既有RDB的快速恢复,又有AOF的数据安全。
选择建议:
如果对数据安全要求高,使用AOF,设置everysec同步策略。如果可以接受几分钟的数据丢失,使用RDB,性能更好。最佳实践是同时开启RDB和AOF,或者使用混合持久化。
3. MySQL的SQL调优方式有哪些?
SQL调优的思路:
SQL调优的核心是减少数据扫描量、减少IO次数、提高查询效率。首先要定位慢SQL,然后分析执行计划,找出瓶颈,最后针对性优化。
定位慢SQL:
开启慢查询日志,设置阈值比如2秒,记录执行时间超过阈值的SQL。通过日志找出需要优化的SQL语句。也可以通过监控系统实时发现慢查询。
分析执行计划:
使用explain命令分析SQL的执行计划。重点关注几个字段:type表示访问类型,最好是ref或range,避免ALL全表扫描。key表示使用的索引,如果是NULL说明没用索引。rows表示扫描行数,越少越好。Extra显示额外信息,要避免Using filesort和Using temporary。
优化方向:
第一是添加索引。根据where条件、order by、group by的字段添加合适的索引。使用联合索引时注意最左前缀原则。使用覆盖索引避免回表查询。
第二是避免索引失效。不要在索引列上使用函数或表达式。避免隐式类型转换。like查询不要以通配符开头。or条件要确保两边都有索引。
第三是优化SQL语句。避免select星号,只查询需要的字段。减少子查询,改用join。但join的表不要太多,一般不超过3个。分页查询使用延迟关联优化。
第四是优化表结构。选择合适的数据类型,能用int不用varchar。字段设置not null,避免null值判断。大字段独立存储,不要和常用字段放一起。
第五是分库分表。数据量大时,单表查询再怎么优化也有瓶颈。可以按照用户ID、时间等维度分表,把数据分散到多个表中。
第六是使用缓存。热点数据放到Redis缓存,减少数据库查询。查询结果缓存起来,设置合理的过期时间。
具体案例:
比如一个订单查询接口很慢,explain发现是全表扫描。分析后发现where条件用了函数year(create_time) = 2024,导致索引失效。优化为create_time between '2024-01-01' and '2024-12-31',添加create_time索引,查询时间从3秒降到50毫秒。
4. JDK 8引入了哪些新特性?Lambda表达式的优势是什么?
Lambda表达式:
Lambda表达式是JDK 8最重要的特性,它允许把函数作为参数传递,简化了代码。Lambda表达式本质上是匿名函数,可以替代匿名内部类。
比如以前创建线程要写匿名内部类,代码很冗长。使用Lambda表达式后,只需要一行代码就能实现。遍历集合、排序、过滤等操作都可以用Lambda简化。
Lambda的优势是代码更简洁、可读性更好。配合Stream API可以实现函数式编程,代码更优雅。
Stream API:
Stream API提供了声明式的数据处理方式。可以对集合进行过滤、映射、排序、聚合等操作,而且支持并行处理。
比如要从用户列表中筛选出年龄大于18岁的用户,然后按年龄排序,取前10个。用传统方式需要写循环、判断、排序、截取,代码很长。用Stream API几行代码就能实现,而且逻辑清晰。
Optional类:
Optional是一个容器类,用于解决空指针异常问题。它可以包含一个值或者为空,提供了一系列方法来处理可能为空的情况。
使用Optional可以避免显式的null检查,代码更优雅。比如获取用户名,如果用户为空返回默认值,用Optional可以链式调用,不需要多层if判断。
接口默认方法:
JDK 8允许在接口中定义默认方法,使用default关键字。这样可以在不破坏现有实现的情况下,给接口添加新方法。
比如List接口添加了sort方法,所有实现类自动拥有这个方法,不需要修改实现类的代码。这解决了接口演化的问题。
新的日期时间API:
JDK 8引入了全新的日期时间API,在java.time包下。新API解决了旧API的很多问题,比如线程不安全、设计混乱等。
LocalDate表示日期,LocalTime表示时间,LocalDateTime表示日期时间。这些类都是不可变的,线程安全的。提供了丰富的方法进行日期计算、格式化等操作。
方法引用:
方法引用是Lambda表达式的简化形式。如果Lambda表达式只是调用一个已存在的方法,可以用方法引用代替,代码更简洁。
方法引用有四种形式:静态方法引用、实例方法引用、对象方法引用、构造方法引用。
这些新特性让Java代码更简洁、更现代化,提高了开发效率。
5. 项目中为什么使用策略模式?有什么优点?
使用场景:
我在做支付系统时使用了策略模式。系统需要支持多种支付方式,包括支付宝、微信支付、银联支付等。每种支付方式的调用接口、参数、签名方式都不一样。
如果用if-else判断支付方式,然后调用不同的支付接口,代码会很臃肿。而且每增加一种支付方式,就要修改原有代码,违反了开闭原则。
策略模式实现:
我定义了一个支付策略接口PayStrategy,包含pay方法。然后为每种支付方式实现这个接口,比如AlipayStrategy、WechatPayStrategy、UnionPayStrategy。
在支付服务中,根据用户选择的支付方式,获取对应的策略实现,调用p
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
Java面试圣经,带你练透java圣经

查看10道真题和解析