一、mybatis:
1、当实体类中的属性名和表中的字段名不一样 ,怎么办
1、使用as关键字起别名
-
<sql id="Base_Column_List">
-
<!--数据库种表的字段 as 实体类属性-->
-
uid as id, userName as name, age as age,
-
email as email, create_time as createTime,
-
update_time as updateTime, is_deleted as deleted
-
</sql>
2、使用resultMap标签映射:column的值为数据库中的字段名,property的值为实体类中的属性名
-
<!-- type:指定需要映射的实体类 -->
-
<resultMap id="userMap" type="User">
-
<!-- column:数据库表中的字段名 -->
-
<!-- property:实体类中的属性 -->
-
<id column="uid" property="id" />
-
<result column="userName" property="name" />
-
<result column="age" property="age" />
-
<result column="email" property="email" />
-
<result column="create_time" property="createTime" />
-
<result column="update_time" property="updateTime" />
-
<result column="is_deleted" property="deleted" />
-
</resultMap>
-
<select id="getUserList" resultMap="userMap">
-
select uid,userName,age,email,create_time,update_time,is_deleted from t_user;
-
</select>
篇幅限制下面就只能给大家展示小册部分内容了。这份面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记【点击此处】即可免费获取
2、#{}和${}的区别是什么
#{}是预编译参数占位符,可以防止sql注入。
${}是字符串替换占位符,无法防止sql注入。
sql注入:sql注入是指攻击者向数据库中插入恶意的sql语句,从而来获取或篡改数据库中的数据。
3、Mybatis 分页插件的原理是什么
MyBatis 分页插件的原理是通过拦截 SQL 执行过程,在执行前和执行后对 SQL 进行改写,添加分页相关的语句,实现数据库分页查询功能。
具体原理包括:
1、拦截器:MyBatis 分页插件通过拦截器拦截 Executor 的 query 方法,在执行 SQL 之前和之后进行处理。
2、SQL 改写:在执行前,插件会将原始 SQL 语句改写成分页查询语句,通常是在原始 SQL 后面添加 LIMIT 或 OFFSET 等关键字,限制返回结果的数量。
3、参数处理:插件还会处理分页相关的参数,如页码和每页数据量,以便构建正确的分页查询语句。
4、结果处理:在执行后,插件会对查询结果进行处理,将结果封装成分页对象,包括总记录数、当前页码、每页数据量等信息。
通过以上步骤,MyBatis 分页插件实现了对 SQL 查询结果的分页处理,使得开发者可以方便地进行数据库分页查询。
4、一对一、一对多的关联查询
1、一对一使用association标签
2、一对多使用collection标签
案例:一个商品对应一个价格,一个价格对应多个商品
实体类:
-
public class Product {
-
private Long id;
-
private String name;
-
private Price price;
-
// Getters and setters
-
}
-
public class Price {
-
private Long id;
-
private Double value;
-
private List<Product> products;
-
// Getters and setters
-
}
xml:
-
<select id="selectProductWithPrice" resultMap="productWithPrice">
-
SELECT p.id AS product_id, p.name, pr.id AS price_id, pr.value
-
FROM product p
-
LEFT JOIN price pr ON p.id = pr.product_id
-
</select>
-
<resultMap id="productWithPrice" type="Product">
-
<id property="id" column="product_id"/>
-
<result property="name" column="name"/>
-
<association property="price" javaType="Price">
-
<id property="id" column="price_id"/>
-
<result property="value" column="value"/>
-
</association>
-
</resultMap>
-
<select id="selectPriceWithProducts" resultMap="priceWithProducts">
-
SELECT pr.id AS price_id, pr.value, p.id AS product_id, p.name
-
FROM price pr
-
LEFT JOIN product p ON pr.product_id = p.id
-
WHERE pr.value > 100;
-
</select>
-
<resultMap id="priceWithProducts" type="Price">
-
<id property="id" column="price_id"/>
-
<result property="value" column="value"/>
-
<collection property="products" ofType="Product">
-
<id property="id" column="product_id"/>
-
<result property="name" column="name"/>
-
</collection>
-
</resultMap>
5、Mybatis 的一级、二级缓存
一级缓存是 MyBatis 默认开启的,作用于同一个 SQLSession 中,生命周期较短。当 SQLSession 关闭时,一级缓存就会被清空。
二级缓存须在 Mapper.xml 中配置,作用于不同的 SQLSession 中,生命周期较长。二级缓存在整个应用程序的生命周期内有效,当应用程序关闭时,二级缓存也会被清空。
总之,一级缓存和二级缓存都旨在提高数据访问的性能并减轻数据库压力,对于相同的查询都是从缓存中获取的。
6、如何获取自动生成的(主)键值
1、在标签中添加一个属性useGeneratedKeys="true"即可。(该属性只能放在insert标签中)
案例:
-
<insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">
-
INSERT INTO users (username, password) VALUES (#{username}, #{password})
-
</insert>
2、使用selectKey标签也行,它可以在执行插入语句数据库之前,通过一个查询来获取主键值。(该标签只能放在insert标签中)
案例:
-
<insert id="insertUser" parameterType="User">
-
<selectKey keyProperty="id" resultType="java.lang.Long" order="AFTER" >
-
SELECT LAST_INSERT_ID() AS id
-
</selectKey>
-
INSERT INTO users (username, password) VALUES (#{username}, #{password})
-
</insert>
二、redis:
1、谈谈你对redis的理解
1、对redis的理解:数据存储在内存中,读取速度快,是一种非关系型数据库。
2、数据结构和用途:Redis支持多种数据结构,如string、hash、list、set、zset,适用于缓存、消息队列和会话存储等场景。
3、分布式特性:Redis支持主从复制和集群模式,实现高可用性和横向扩展。
2、Redis 的数据类型
1、字符串 (String):
简述: 存储字符串、整数或浮点数等基本数据类型。
应用场景: 缓存、计数器、计时器等。
2、哈希 (Hash):
简述: 存储对象的属性和对应值的键值对集合。
应用场景: 存储用户信息、对象属性等。
篇幅限制下面就只能给大家展示小册部分内容了。这份面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记【点击此处】即可免费获取
3、列表 (List):
简述: 按插入顺序排序的字符串元素集合,支持头部和尾部的增删改操作。
应用场景: 消息队列、任务队列等。
4、集合 (Set):
简述: 无序的字符串集合,不允许重复元素。
应用场景: 标签系统、好友关系等。
5、有序集合 (Sorted Set):
简述: 有序集合,元素按分数升序排列,每个元素都有一个分数。
应用场景: 排行榜、范围查询等需要按分数排序的场景。
3、Redis 是单进程单线程的吗
是的。
4、Redis 的淘汰策略
1、LRU(Least Recently Used):淘汰最近最少使用的数据。
2、LFU(Least Frequently Used):淘汰最少频繁使用的数据。
3、TTL(Time To Live):自动淘汰过期的数据。
4、Random(随机淘汰):随机选择一个数据进行淘汰。
5、No Eviction(无淘汰):当内存达到最大限制时,拒绝写入新的数据,而不进行淘汰。
5、redis 过期键的删除策略
Redis 中过期键的删除策略包括定期删除和惰性删除。
定期删除:Redis 默认采用的是定期删除策略。在设置键的过期时间时,同时创建一个定时器,在键的过期时间到达时,定时器会检查该键是否过期,如果过期则删除。定期删除可能会带来性能问题,特别是当大量键在短时间内过期时,可能导致性能下降。
惰性删除:在每次获取键时,Redis 会先检查键是否过期,如果过期则删除。这种策略避免了定期删除可能带来的性能问题,但是可能会造成过期键一直占用内存空间,直到被访问时才删除,增加了内存使用。
定期删除和惰性删除可以结合使用,定期删除主要用于辅助惰性删除,确保内存占用在可控范围内。
6、怎么理解 Redis 事务
Redis 事务是一种将多个命令打包成一个操作单元,然后一次性、顺序执行的机制。在 Redis 中,事务是通过 MULTI、EXEC、DISCARD 和 WATCH 等命令来实现的。
1、MULTI: 开启一个事务,标志着事务的开始。
2、EXEC: 执行事务中的所有命令。
3、DISCARD: 取消事务,放弃执行事务中的所有命令。
4、WATCH: 监视一个或多个键,当这些键被其他客户端修改时,事务将被打断。
在 Redis 事务中,命令序列会被一次性发送到服务器执行,直到 EXEC 命令被调用为止。事务中的命令要么全部执行成功,要么全部执行失败,不存在部分执行的情况。这种原子性保证了事务的一致性。
通过使用 Redis 事务,可以将多个命令打包成一个原子操作单元,保证了数据的一致性,同时减少了网络通信的开销,提高了性能。
7、redis雪崩,击穿,穿透,以及在项目中如何解决的
在 Redis 中,存在三种常见的问题,即雪崩、击穿和穿透,它们分别是:
1、雪崩:指在缓存中大量的数据同时过期失效,导致大量的请求直接访问数据库,造成数据库负载剧增,甚至宕机的情况。这种现象类似于雪崩一样,一旦发生,会导致系统的崩溃。
2、击穿:指查询一个不存在的键,导致请求直接访问数据库,由于缓存中不存在该键,所以会直接请求数据库,如果并发量较大,会导致数据库负载过大。
3、穿透:指查询一个不存在的数据,而且查询的条件恒为真,导致请求直接访问数据库,如果请求量很大,会对数据库造成很大的压力。
针对这些问题,可以采取以下解决方案:
1、对于雪崩问题,可以采取多种手段,如设置不同的过期时间、使用缓存预热、实现缓存数据的永不过期策略等,以减轻缓存数据同时失效的情况。
2、对于击穿问题,可以使用互斥锁或分布式锁等机制,防止大量请求同时查询数据库,同时可以考虑使用哨兵节点等方式提高 Redis 的高可用性。
3、对于穿透问题,可以在缓存中设置空值或默认值,并且可以使用布隆过滤器等技术拦截恶意请求,减少对数据库的直接访问。
综上所述,针对不同的问题,可以采取不同的策略和技术手段来解决,在项目中需要根据具体情况综合考虑采取适当的措施来保障系统的稳定性和性能。
8、redis在你项目中的应用场景
缓存token、缓存树状图、获取系统最大限制长度(例如excel的导入和导出最大长度)。
9、谈谈redis的哨兵机制
作用:Redis的哨兵机制监控主库是否故障,一旦主库宕机,哨兵会自动将一个从库切换成主库,无需人工干预,确保服务的连续性和可用性。这种自动化的故障转移减少了人工干预的需要,提高了系统的稳定性和可靠性。
原理:哨兵通过发送命令,等待redis响应,从而监控多个运行的redis实例。
10、redis持久化机制,RDB和AOF
RDB(Redis DataBase)和 AOF(Append Only File)是Redis提供的两种持久化机制。
RDB持久化是一种快照的方式,定期将内存中的数据集快照写入磁盘。它的优点是生成的快照文件相对较小,恢复速度快,适合用于备份数据或者灾难恢复。缺点是可能会在发生故障时丢失最后一次持久化之后的数据。
AOF持久化是一种追加写入日志文件的方式,记录了服务器执行的所有写操作命令,以此来记录数据变更。AOF文件在Redis重启时会根据文件内容重新执行命令来恢复数据。它的优点是能够保证较高的数据完整性和持久性,可以根据需要选择不同的同步策略。缺点是相比RDB,AOF文件通常较大,恢复速度相对较慢,且可能会有部分数据丢失。
11、谈谈redis集群
1、主从复制模式:
在主从复制模式中,主库负责处理客户端的读写请求,从库提供读操作的服务。当主库宕机后,需要手动将某个从库转换成新的主库,这个过程需要人工干预。
2、主从哨兵模式:
在主从哨兵模式中,除了主库和从库外,还有一个或多个哨兵节点负责监控主库的运行状态。当主库宕机后,哨兵会根据投票的方式自动将某个从库转换成新的主库,无需人工干预。
3、Cluster集群模式:
Redis Cluster是redis提供的一种分布式集群模式,该模式将数据分散存储在多个节点上,提供了高性能,高可用性和可伸缩性的数据存储解决方案。
三、mysql:
1、MySQL事务
1、原子性(Atomicity):指事务中的操作要么全部成功,要么全部失败。不存在部分操作成功而其他操作失败的情况。
2、一致性(Consistency):指事务执行前后,数据库从一个一致性状态转换到另一个一致性状态。即事务开始前和结束后,数据库的完整性约束没有被破坏。
3、隔离性(Isolation):指多个事务并发执行时,每个事务都相互隔离,彼此不会互相干扰。不同的隔离级别(读未提交、读已提交、可重复读、可串行化)决定了事务之间的隔离程度。
4、持久性(Durability):指一旦事务提交,对数据库的修改就会永久保存在数据库中,即使数据库发生故障也不会丢失提交的数据。持久性通过将事务的日志保存在磁盘上来实现。
对于MySQL,可以使用BEGIN、COMMIT和ROLLBACK语句来控制事务的开始、提交和回滚。
2、MySQL索引,索引失效场景
索引:
1、普通索引:最基本的索引类型,用于提高数据的查询速度。
2、主键索引:同一张表中只能有一个,值不能为NULL,创建主键时会自动创建,主要用于保证每一行数据的唯一性。
3、唯一索引:同一张表中可以有多个,用于保证字段的唯一性以及提高数据的查询速度。
4、外键索引:创建外键时会自动创建,使两表之间产生关联。
5、联合索引:同时提高多个字段的查询速度,需满足最左匹配原则,否则会索引失效。
最左匹配原则:
MySQL 的最左匹配原则是指在使用联合索引(也称为多列索引)时,查询条件中的列顺序应该与索引定义的列顺序相匹配,并且优先使用左边的列。
具体来说,如果在一个联合索引中定义了多个列,例如 (列 1, 列 2, 列 3) ,那么在查询时,
MySQL 会首先根据列 1 进行索引搜索。如果列 1 的值存在多个匹配项,那么 MySQL 会继续根据列 2 的值进行筛选,以此类推。
如果查询条件中只使用了联合索引的一部分列,例如只使用了列 2 和列 3,而没有使用列 1,那么索引仍然可以生效,但效果可能会受到一定影响。在这种情况下,MySQL 会利用已使用的列进行索引搜索,但无法利用索引的全部效果。
最左匹配原则的目的是为了提高查询效率和索引的利用效率。通过按照索引定义的顺序使用列,可以更好地利用索引的有序性和筛选能力,减少需要扫描的数据量,从而提高查询性能。
需要注意的是,最左匹配原则并不是绝对的,实际的查询优化还会受到其他因素的影响,例如数据分布、数据量、查询的复杂度等。在实际应用中,需要根据具体情况进行测试和分析,以确定最合适的索引策略和查询方式。
索引失效场景:
1、全表扫描
2、索引列进行了计算
3、使用函数进行索引列的操作
4、like操作符使用通配符开头
5、or条件中的部分条件没有索引
6、联合索引不满足最左匹配原则
3、sql优化
1、使用索引:为经常用于查询条件的列创建索引,加快数据检索速度。
2、避免使用select *:只检索需要的列,减少数据传输和处理时间。
3、适当分页查询:使用limit和offset进行分页,避免一次性加载大量数据。
4、使用连接(JOIN)优化:使用inner/left/right join等连接方式,避免笛卡尔积。
5、避免使用子查询:尽量避免使用子查询,可以使用join或者临时表代替。
6、使用 EXPLAIN 分析查询:通过EXPLAIN关键字分析查询执行计划,找出慢查询和需要优化的地方。
篇幅限制下面就只能给大家展示小册部分内容了。这份面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记【点击此处】即可免费获取
7、定期维护和优化数据库:定期清理无用数据、重建索引、分析表统计信息等,保持数据库性能稳定。
8、合理使用事务:将需要同时执行的操作放在同一个事务中,减少事务的开销。
9、定期优化数据库结构:定期检查和优化数据库表结构,包括索引、字段类型等。
10、适当使用缓存:对一些频繁查询但不经常变化的数据,可以考虑使用缓存,减少数据库压力。
11、避免在 WHERE 子句中对字段进行函数操作:这会导致索引失效,影响查询性能。
12、合理使用字段类型:选择合适的字段类型,避免使用过大或不必要的数据类型,减少存储空间和提高查询效率。
4、MySQL 中有哪几种锁
5、MySQL 中 InnoDB 支持的四种事务隔离级别名称,以及逐级之间的区别
1、读未提交(read uncommitted):
读未提交是指事务A可以读取到事务B未提交的数据。
这种隔离级别存在一种脏读现象,我们称读到了脏数据。
读未提交是最低的隔离级别。
2、读已提交(read committed):
读未提交是指事务A只能读取到事务B提交之后的数据。
这种隔离级别解决了脏读现象,但是存在一种不可重复读现象。
不可重复读是指在事务开启之后,第一次读到的数据是3条,当前事务还没有结束,可能第二次再读取到的时候,读到的数据就是4条,3不等于4称为不可重复读取。这种隔离级别是比较真实的数据,每一次读到的数据是绝对的真实。
oracle数据库默认的隔离级别就是读已提交。
3、可重复读(repeatable read):
可重复读是指事务A开启之后,不管是多久,每一次在事务A中读取到的数据都是一致的。即使事务B将数据已经修改,并且提交了,事务A读取到的数据还是没有发生变化,这就是可重复读。
这种隔离级别解决了不可重复读现象,但是存在一种幻读现象。
mysql数据库默认的隔离级别就是可重复读。
4、可串行化(serializable):
可串行化每一次读取到的数据都是最真实的,但是效率是最低的。
可串行化解决了所有的问题。
可串行化是最高的隔离级别。
6、CHAR 和 VARCHAR 的区别
1、存储方式:
CHAR 类型固定长度,当存储字符数不足指定长度时会用空格填充,占用空间固定。
VARCHAR 类型可变长度,实际占用的空间根据存储的数据长度而变化。
2、空间利用:
对于包含大量可变长度字符串的列,使用 VARCHAR 可以节省空间,因为它只存储实际使用的数据长度。
对于固定长度的字符串,使用 CHAR 可能更节省空间,因为它不需要存储额外的长度信息。
3、查询效率:
在查询和排序等操作时,CHAR 类型的效率可能更高,因为它的存储方式是固定长度的,无需额外的长度信息,而 VARCHAR 则需要额外的长度信息。
7、mysql的 ACID
1、原子性(Atomicity):指事务中的操作要么全部成功,要么全部失败。不存在部分操作成功而其他操作失败的情况。
2、一致性(Consistency):指事务执行前后,数据库从一个一致性状态转换到另一个一致性状态。即事务开始前和结束后,数据库的完整性约束没有被破坏。
3、隔离性(Isolation):指多个事务并发执行时,每个事务都相互隔离,彼此不会互相干扰。
不同的隔离级别(读未提交、读已提交、可重复读、可串行化)决定了事务之间的隔离程度。
4、持久性(Durability):指一旦事务提交,对数据库的修改就会永久保存在数据库中,即使数据库发生故障也不会丢失提交的数据。持久性通过将事务的日志保存在磁盘上来实现。
对于MySQL,可以使用BEGIN、COMMIT和ROLLBACK语句来控制事务的开始、提交和回滚。
8、查询索引的sql
SHOW INDEX FROM table_name;
9、查询当前数据库版本的sql
SELECT VERSION();
10、mysql 中 in 和 exists 区别
IN 主要用于比较某个字段的值是否在子查询结果集中,适用于简单的值匹配查询。
-
SELECT column_name(s)
-
FROM table_name
-
WHERE column_name IN (SELECT column_name FROM table_name WHERE condition);
EXISTS 主要用于检查子查询是否返回结果,适用于需要判断子查询是否为空的情况。通常用于复杂的条件过滤和连接查询。
-
SELECT column_name(s)
-
FROM table_name
-
WHERE EXISTS (SELECT column_name FROM table_name WHERE condition);
11、mysql统计函数有哪些
COUNT:用于统计查询结果集中的行数。
SUM:用于计算数值列的总和。
AVG:用于计算数值列的平均值。
MAX:用于获取数值列的最大值。
MIN:用于获取数值列的最小值。
12、mysql存储引擎有哪些
InnoDB:MySQL的默认存储引擎,支持事务、行级锁、外键等特性,适合于需要高并发、事务安全的应用场景。
MyISAM:适合于读密集型的应用,不支持事务和行级锁,但是速度快、存储占用小。
MEMORY:将数据存储在内存中,适合于临时表或者存储较小的数据集。
CSV:将数据以CSV格式存储在文件中,适合于导入导出数据。
ARCHIVE:使用压缩算法来存储数据,适合于存储大量历史数据。
NDB Cluster:适合于高可用、高并发的分布式数据库集群环境。
13、score表中有id、name、score三个字段,查询出每个成绩对应的数量,升序排
-
SELECT score, COUNT(*) AS count
-
FROM score
-
GROUP BY score
-
ORDER BY score ASC;
篇幅限制下面就只能给大家展示小册部分内容了。这份面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记【点击此处】即可免费获取
13、student表中有id,name字段,只查出name重复的字段
-
SELECT name
-
FROM student
-
GROUP BY name
-
HAVING COUNT(*) > 1;
四、springboot:
1、Spring Boot 有哪些优点和缺点
优点:
1、快速启动:Spring Boot 提供了快速启动器(starter)和自动配置,使项目创建和部署变得更加简单快捷。
2、简化配置:采用约定大于配置的原则,减少了繁琐的配置工作,提供了默认配置,开发人员可以根据需要进行自定义配置。
3、集成简单:Spring Boot 集成了大量常用的框架和组件,如Spring MVC、Spring Data、Spring Security等,大大降低了集成的复杂度。
4、内嵌服务器:Spring Boot 内置了多种常用的Web服务器,如Tomcat、Jetty等,无需额外配置,即可快速启动应用程序。
5、微服务支持:Spring Boot 对微服务架构提供了良好的支持,集成了Spring Cloud等微服务相关的技术,方便开发和管理微服务应用。
缺点:
1、学习曲线:对于初学者来说,Spring Boot 可能有一定的学习曲线,需要掌握Spring框架的基础知识,并了解Spring Boot的特性和用法。
2、过度依赖:Spring Boot 集成了大量的框架和组件,有时候可能会导致项目产生过多的依赖,增加了项目的复杂性和维护成本。
3、自动配置复杂性:尽管Spring Boot的自动配置功能可以简化项目的配置,但有时候也可能会导致配置变得复杂难以理解,特别是在定制自动配置时。
4、集成冲突:由于Spring Boot集成了多个框架和组件,可能会出现版本冲突或集成问题,需要谨慎处理依赖关系和版本兼容性。
5、项目启动速度:由于Spring Boot需要加载大量的自动配置和依赖,有时候可能会导致项目启动速度较慢,尤其是在应用程序规模较大时。
2、SpringBoot 自动装配
Spring Boot 自动装配是指 Spring Boot 框架根据项目的依赖和配置,自动配置应用程序的各种组件和功能,简化了开发过程,提高了开发效率。
在 Spring Boot 中,通过 @EnableAutoConfiguration 注解来启用自动配置功能。Spring Boot 根据应用程序的依赖,例如 Maven 或 Gradle 中引入的各种 Starter 依赖,以及配置文件中的配置项,自动配置应用程序所需的各种组件,如数据库连接、Web 容器、消息队列等。
Spring Boot 自动配置的原理是通过条件注解和 Spring Boot 提供的各种 Starter 来实现的。条件注解根据项目中的依赖和配置来判断是否需要应用某项配置,如果符合条件,则自动配置相应的组件;Starter 是一种特殊的依赖,它包含了一系列的默认依赖和配置,可以快速集成各种常用的技术栈,如 Spring MVC、JPA、Redis 等。
通过 Spring Boot 的自动配置,开发者无需手动配置大量的 XML 文件或 Java 代码,而是可以专注于业务逻辑的开发,大大简化了项目的配置和搭建过程,提高了开发效率。
3、SpringBoot 有哪几种读取配置的方式
1、使用value注解:
使用@Value注解可以直接将配置文件中的属性值注入到Spring Bean中。
yml:
-
my:
-
property: example-value
代码:
-
@Value("${my.property}")
-
private String myProperty;
2、使用ConfigurationProperties注解:
yml:
-
my:
-
property1: value1
-
property2: value2
代码:
-
@Component
-
@ConfigurationProperties(prefix = "my")
-
public class MyProperties {
-
private String property1;
-
private String property2;
-
// getters and setters
-
}
3、使用Environment接口:
-
@Autowired
-
private Environment env;
-
public void someMethod() {
-
String property = env.getProperty("my.property");
-
}
五、spring:
1、Spring常用注解
1、@Autowried:实现服务类的自动注入,默认按照byType的方式进行装配。
2、@Post/Get/Put/DeleteMapping:分别用于处理POST/GET/PUT/DELETE请求的方法。
3、@Controller:用于处理Web请求。
4、@Value:用于注入配置文件中的属性值。
5、@Transactional:声明方法或类在事务的管理下运行。
6、@Service:被该注解标识的实现类会被Spring交给Ioc去管理。
7、@RequestParam:将请求参数绑定到方法参数上。
8、@PathVariable:将URL中的路径参数绑定到方法参数上。
还有常见的@RequestMapping、@RequestParam、@ResponseBody、@Repository、@Component等Spring常用注解。
注解Autowried和resource的区别:
Autowried是Spring的注解,默认按照byType的方式进行装配
resource是JavaEE的注解,默认按照byName的方式进行装配
2、spring的aop和ioc的区别
IOC:控制反转,也称依赖注入。在没有Spring之前,若需要频繁的创建对象,对于开发者而言是费时费事的;出现Spring之后,Spring会将频繁创建对象的这个一过程都交给ioc去处理,对于开发者而言可以将省去的时间都集中在业务层面,省时省事。
应用场景:
篇幅限制下面就只能给大家展示小册部分内容了。这份面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记【点击此处】即可免费获取
1、被Service注解修饰的实现类会被Spring交给Ioc去处理
2、被注入的服务类会被Spring交给Ioc去处理
3、被Configuration注解修饰的应用配置类以及类中的Bean,会被Spring交给Ioc去处理
AOP:面向切面编程。它是通过将代码在程序的运行过程中切入或切出到某个类的方法中。底层主要是通过Jdk动态代理和Cglib动态代理来实现的。Jdk动态代理则是提高反射机制和拦截器来实现的,而Cglib动态代理则是提高ASM框架来实现的。
应用场景:
1、被Transactional注解修饰的方法,通过aop去实现事务的一致性
2、日志记录,在方法执行前后,记录方法的入参,返回值、执行时间等信息
3、异常处理,在方法执行后捕获异常,实现异常的同一处理逻辑
3、bean的生命周期
1、实例化(Instantiation):在容器启动或需要时,根据配置信息实例化Bean对象。
2、初始化(Initialization):在Bean实例化后,容器会调用初始化方法,如构造函数、@PostConstruct注解的方法等,对Bean进行初始化设置。
3、使用(Usage):在初始化后,Bean会被容器管理,应用程序可以通过容器获取和使用Bean,执行各种业务逻辑。
4、销毁(Destruction):在应用程序关闭或Bean不再需要时,容器会调用销毁方法,如@PreDestroy注解的方法等,对Bean进行清理和资源释放。
六、微服务:
1、谈谈你对微服务的理解,以及和单体架构的区别
微服务架构是一种软件架构风格,其中应用程序被拆分成一组小型、松耦合的服务,每个服务专注于特定的业务功能,并通过轻量级通信机制进行交互。微服务架构强调将应用程序拆分成多个服务,每个服务都可以独立部署、扩展和更新,以提高灵活性、可扩展性和快速交付能力。
与传统的单体架构相比,微服务架构有以下区别:
1、拆分度和模块化:
单体架构通常由一个单独的应用程序组成,所有功能和业务逻辑都集中在一个代码库中。而微服务架构将应用程序拆分成多个小型服务,每个服务专注于特定的业务功能,实现了更高的拆分度和模块化。
2、技术多样性:
单体架构通常使用统一的技术栈和编程语言开发整个应用程序。而微服务架构允许每个服务使用不同的技术栈和编程语言,根据业务需求选择最适合的技术,提高了灵活性和创新性。
3、部署和扩展:
单体架构的应用程序通常作为一个整体进行部署和扩展,无法针对特定功能进行独立部署和扩展。而微服务架构允许每个服务独立部署和扩展,根据业务需求对单个服务进行调整和优化,提高了灵活性和可扩展性。
4、团队组织和自治性:
单体架构通常由一个团队负责开发和维护整个应用程序,所有功能和业务逻辑都集中在一个代码库中。而微服务架构允许每个服务由专门的团队负责开发和维护,提高了团队的自治性和创造力,促进了团队之间的协作和交流。
5、故障隔离和弹性:
单体架构中一个模块的故障可能导致整个应用程序的崩溃,难以实现故障隔离和弹性。而微服务架构将应用程序拆分成多个服务,一个服务的故障不会影响其他服务的运行,提高了系统的弹性和容错性。
总的来说,微服务架构强调将应用程序拆分成多个小型、松耦合的服务,通过独立部署、技术多样性、团队自治性等特点实现了更高的灵活性、可扩展性和快速交付能力,但也增加了系统的设计和运维成本。
2、nacos心跳机制
nacos首先会计算出服务的最新一次心跳时间与当前时间的1差值,接着再于系统指定的阈值作比较,如果大于指定阈值,Nacos会将其服务标记为不健康或将其从注册列表中移除。
如果服务恢复并重新注册到Nacos,它将再次变为健康状态。
3、对gateway的理解
Gateway(网关)是一个充当访问点的服务器或服务,它作为系统的入口点,接收来自客户端的请求,并将请求转发到后端的微服务或其他系统。Gateway 在软件架构中起着重要的作用,可以实现诸如安全认证、请求路由、负载均衡、缓存、日志记录等功能,从而实现对系统的统一访问和管理。
在微服务架构中,API Gateway 是一种常见的网关形式,它负责管理和处理来自客户端的 API 请求,并将这些请求转发到后端的微服务。API Gateway 可以实现路由转发、安全认证、授权、限流、日志记录等功能,同时还可以对请求进行转换和加工,以适配后端微服务的接口。
总的来说,Gateway 提供了一个中心化的访问点,可以实现对系统的统一管理和控制,提高系统的安全性、性能和可用性,同时也方便了系统的扩展和维护。Gateway 在现代软件架构中扮演着重要的角色,是构建可靠、高效、安全的系统的关键组件之一。
4、微服务的优缺点
优点:
1、模块化和松耦合:微服务架构将应用拆分成多个小型服务,每个服务都专注于特定的业务功能,使得系统更加模块化和松耦合,便于开发、测试和维护。
2、灵活性和可扩展性:每个微服务都可以独立部署、升级和扩展,可以根据业务需求对单个服务进行调整和优化,从而提高系统的灵活性和可扩展性。
3、技术多样性:微服务架构允许每个服务使用不同的技术栈和编程语言,可以选择最适合特定业务需求的技术,从而提高开发效率和灵活性。
4、弹性和容错性:微服务架构将应用拆分成多个服务,一个服务的故障不会影响其他服务的运行,提高了系统的弹性和容错性。
5、快速部署和交付:微服务架构支持持续集成和持续交付,可以快速部署新功能和更新,缩短开发周期,提高交付效率。
6、更好的团队组织:每个微服务都可以由专门的团队负责开发和维护,提高了团队的自治性和创造力,促进了团队之间的协作和交流。
缺点:
1、分布式系统复杂性:微服务架构引入了分布式系统的复杂性,包括服务间通信、服务注册与发现、服务治理、数据一致性等方面的挑战,增加了系统的设计和运维成本。
2、服务间通信开销:微服务架构通过网络进行服务间通信,可能引入额外的延迟和带宽消耗,影响系统的性能和吞吐量。
3、数据管理:微服务架构中每个服务都有自己的数据存储,可能导致数据一致性和数据管理方面的挑战,增加了系统的复杂性和管理成本。
4、部署和监控:微服务架构中涉及多个服务,需要对每个服务进行独立部署和监控,增加了部署和运维的工作量。
5、服务拆分和边界定义:微服务架构需要对系统进行合理的拆分和边界定义,划分服务的粒度需要平衡系统的灵活性和复杂性,需要经过合理的设计和评估。
6、技术选型和管理:微服务架构允许每个服务使用不同的技术栈和编程语言,可能导致技术选型和管理方面的挑战,需要进行合理的规划和管理。
七、java基础:
1、获得一个类的类对象有哪些方式
1、使用类名的.class语法:
Class<?> clazz = MyClass.class;
2、调用对象的getClass()方法:
-
MyClass obj = new MyClass();
-
Class<?> clazz = obj.getClass();
3、使用Class类的forName()静态方法:
Class<?> clazz = Class.forName("com.example.MyClass");
4、使用类加载器ClassLoader的loadClass方法:
-
ClassLoader classLoader = MyClass.class.getClassLoader();
-
Class<?> clazz = classLoader.loadClass("com.example.MyClass");
2、在 Java 中,如何跳出当前的多重嵌套循环
在 Java 中,要跳出多重嵌套循环,可以使用带标签的 break 语句。具体步骤如下:
1、在外层循环之前使用一个标签,如 outer。
2、在需要跳出多重嵌套循环的地方,使用 break outer; 语句。
以下是一个示例代码:
-
outerLoop:
-
for (int i = 0; i < 5; i++) {
-
for (int j = 0; j < 5; j++) {
-
if (i * j > 6) {
-
System.out.println("Breaking out of outerLoop at i = " + i + " and j = " + j);
-
break outerLoop;
篇幅限制下面就只能给大家展示小册部分内容了。这份面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记【点击此处】即可免费获取
-
}
-
System.out.println(i + " " + j);
-
}
-
}
在上面的示例中,当 i * j 大于 6 时,程序会输出提示信息并跳出外层循环。
3、Java 中有几种类型的流
1、字节流(Byte Streams):字节流以字节为单位进行读写操作,适用于处理二进制数据。主要包括InputStream和OutputStream。
2、字符流(Character Streams):字符流以字符为单位进行读写操作,适用于处理文本数据。主要包括Reader和Writer。
3、缓冲流(Buffered Streams):缓冲流在字节流和字符流的基础上增加了缓冲区,提高了读写性能。主要包括BufferedInputStream、BufferedOutputStream、BufferedReader和BufferedWriter。
4、对象流(Object Streams):对象流用于读写Java对象,可以直接将对象写入流或从流中读取对象。主要包括ObjectInputStream和ObjectOutputStream。
5、数据流(Data Streams):数据流用于读写基本数据类型和字符串,提供了直接读写基本类型数据的方法。主要包括DataInputStream和DataOutputStream。
6、文件流(File Streams):文件流用于读写文件数据,可以直接与文件进行交互。主要包括FileInputStream和FileOutputStream。
4、java创建对象有哪些方式
1、使用构造方法创建对象:
-
public class Main {
-
public static void main(String[] args) {
-
// 创建对象
-
Person person = new Person("Alice", 25);
-
// 使用对象
-
System.out.println("Name: " + person.getName() + ", Age: " + person.getAge());
-
}
-
}
2、使用静态工厂方法创建对象:
-
public class Main {
-
public static void main(String[] args) {
-
// 创建对象
-
Person person = Person.createPerson("Bob", 30);
-
// 使用对象
-
System.out.println("Name: " + person.getName() + ", Age: " + person.getAge());
-
}
-
}
3、使用反射创建对象:
-
import java.lang.reflect.Constructor;
-
import java.lang.reflect.InvocationTargetException;
-
public class Main {
-
public static void main(String[] args) {
-
// 使用反射创建对象
-
try {
-
Class<?> clazz = Class.forName("Person");
-
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
-
Person person = (Person) constructor.newInstance("Charlie", 35);
-
// 使用对象
-
System.out.println("Name: " + person.getName() + ", Age: " + person.getAge());
-
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
-
e.printStackTrace();
-
}
-
}
-
}
4、使用克隆创建对象:
-
public class Main {
-
public static void main(String[] args) {
-
// 创建对象
-
Person person1 = new Person("David", 40);
-
Person person2 = null;
-
try {
-
person2 = (Person) person1.clone();
-
// 使用对象
-
System.out.println("Name: " + person2.getName() + ", Age: " + person2.getAge());
-
} catch (CloneNotSupportedException e) {
-
e.printStackTrace();
-
}
-
}
-
}
5、列出一些你常见的运行时异常
1、NullPointerException(空指针异常):
-
String str = null;
-
System.out.println(str.length()); // 抛出 NullPointerException
2、ArrayIndexOutOfBoundsException(数组下标越界异常):
-
int[] arr = new int[5];
-
System.out.println(arr[5]); // 抛出 ArrayIndexOutOfBoundsException
3、ClassCastException(类转换异常):
-
Object obj = new Integer(10);
-
String str = (String) obj; // 抛出 ClassCastException
4、NumberFormatException(数字格式异常):
-
String str = "abc";
-
int num = Integer.parseInt(str); // 抛出 NumberFormatException
5、ArithmeticException(算术异常):
int result = 10 / 0; // 抛出 ArithmeticException
6、ConcurrentModificationException(并发修改异常):
-
List<String> list = new ArrayList<>();
-
list.add("A");
-
for (String s : list) {
-
list.remove(s); // 抛出 ConcurrentModificationException
-
}
7、IllegalArgumentException(非法参数异常):
-
int age = -5;
-
if (age < 0) {
-
throw new IllegalArgumentException("年龄不能为负数");
-
}
8、IllegalStateException(非法状态异常):
-
List<String> list = Collections.emptyList();
-
list.add("A"); // 抛出 IllegalStateException
9、IndexOutOfBoundsException(索引越界异常):
-
List<String> list = new ArrayList<>();
-
list.add("A");
-
System.out.println(list.get(1)); // 抛出 IndexOutOfBoundsException
10、NoSuchElementException(没有元素异常):
-
List<String> list = new ArrayList<>();
-
Iterator<String> iterator = list.iterator();
-
System.out.println(iterator.next()); // 抛出 NoSuchElementException
篇幅限制下面就只能给大家展示小册部分内容了。这份面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记【点击此处】即可免费获取