Agent 会先改变代码评审,而不是完全替代编码
Agent 会先改变代码评审,而不是完全替代编码AI 编程工具让代码生产速度大幅提升,但代码审查速度没有同步提升。
这制造了一个新的瓶颈:审查队列变长、大型 PR 被”扫一眼就过”、人类审查者疲劳加剧。Agent 最先切入的,不是取代程序员写代码,而是接管审查流程中结构化、可规模化复制的部分。
审查正在成为瓶颈Anthropic 内部数据显示,在使用 Claude Code Review 之前,只有 16% 的 PR 收到实质性审查意见。这意味着 84% 的 PR 只是被快速浏览后就合并了。
原因很直接:
AI 让单个工程师的代码产出增长了约 200%。
但审查者还是那些人,每天还是那么多小时。
PR 数量增加、单个 PR 复杂度上升、审查者上下文切换成本更高。
结果不是代码质量下降,而是质量保障体系开始跟不上生产节奏。
为什么 Agent 先改变的是审查?代码评审有几个特点,让它特别适合 Agent:
1. 任务高度结构化审查有明确的输入(diff、测试、上下文)和输出(评论、建议、风险标记)。这比”从零写一个新功能”更容易被形式化。
2. 上下文可枚举一次 PR 改动了什么 ...
为什么模块化单体正在回归?
为什么模块化单体正在回归?微服务曾经是一种信仰。
2015 到 2020 年间,几乎所有技术大会都在讲 Netflix、Amazon、Google 的微服务故事。结论是:大公司用了,我们也应该用。于是无数团队把系统拆成十几个、几十个服务,仿佛服务数量本身就是工程成熟度的指标。
2026 年,钟摆正在回摆。不是回到混乱的大泥球,而是回到一种更克制的中间态:模块化单体。
发生了什么?微服务被过度推销了。
Netflix、Amazon 采用微服务,是为了解决数百个工程团队、数亿用户带来的问题。这些问题对于一家 20 人的初创公司来说并不存在。但很多人忽略了这个前提,直接复制了答案。
结果是可预测的:
服务发现、分布式追踪、网络可靠性、数据一致性、部署编排——基础设施工作吞噬了大量本应用于产品的工程能力。
一个原本简单的功能,现在要跨多个服务协调部署。
调试生产问题意味着追踪几十个服务各自的日志和监控。
到了 2023 年前后,一些公司开始公开往回走。Amazon Prime Video 团队发布案例:将微服务整合为单体后,**成本降低 90%**。Shopify 则一直坚持自己的模块化 ...
AI 时代,后端工程师的哪些能力正在贬值?
AI 时代,后端工程师的哪些能力正在贬值?2026 年,后端工程师这个群体正在经历一次静默而剧烈的价值重估。
不是岗位消失,而是市场对”后端工程师”的定义在重写。过去十年里被视为核心竞争力的许多能力,正在快速贬值;而另一些长期被低估的能力,突然变得稀缺。
这不是贩卖焦虑,而是一组正在发生的信号。
一组值得正视的数据
Anthropic 内部数据:生产环境超过 80% 的代码由 Claude 生成,工程师日均代码产出提升约 8 倍。
猎聘 2026 报告:纯编码岗位招聘量暴跌 **52%**,但编程相关岗位总量反增 15%。
GitClear 2026 报告:AI 参与编写的代码,一年内有 47% 被完全重写。
智联招聘 2026 一季度报告:普通后端、前端开发岗位需求同比下降 **52%**。
麦可思《2026 年中国大学生就业报告》:计算机类专业跌出绿牌榜,自动化专业首次跻身绿牌。
这些数据拼在一起,指向一个结论:**市场不再需要”会写代码的人”,市场需要”能用 AI 解决问题的人”**。
这两个身份曾经高度重合,现在正在快速分离。
正在贬值的能力1. 纯语法与 API 记忆过 ...
MyBatis ResultMap 吞行问题
MyBatis ResultMap 吞行问题
你写了一对多关联查询,数据库中明明有 10 行数据,MyBatis 返回的列表却只有 3 条。剩下的 7 行去哪了?这就是经典的 ResultMap “吞行”问题。
现象:数据去哪了?假设你有一张订单表 t_order 和一张订单明细表 t_order_item,一个订单可以包含多个商品明细:
123456789101112-- 订单CREATE TABLE t_order ( id BIGINT PRIMARY KEY, order_no VARCHAR(32));-- 订单明细CREATE TABLE t_order_item ( id BIGINT PRIMARY KEY, order_id BIGINT, product_name VARCHAR(64));
你写了一个 SQL 用 JOIN 关联查询:
123456789<select id="getOrders" resultMap="OrderResultMap"> SELECT ...
好文章收集
文字收集原则:同话题文章取最优,同话题多文章必须有多文章的理由
AI彻底爆了!一文吃透AIGC、Agent、MCP的概念和关系
埃隆马斯克 - 放眼未来 无所畏惧
埃隆马斯克 - 放眼未来 无所畏惧
doris物化视图
Doris物化视图Apache Doris 物化视图详解1. 概述物化视图是一种预计算和储存数据的机制,它通过将复杂查询预算结果以视图的形式保存,以提高进一步查询的性能。对于大数据分析场景,物化视图可以最大稍少进一步计算,为 BI 分析和报表运行提供支持。
Apache Doris 作为一个面向分布式数据库分析的 MPP 架构,支持为大规模数据进行实时分析和回馈。物化视图是它的一个重要特性,可用于提升查询性能。
2. Doris 中物化视图的特点
自动选择符合的物化视图:在执行查询时,Doris 会根据查询的 SQL 自动匹配适合的物化视图,无需手动指定。
增量更新与数据不一致性操作:物化视图通过增量更新保证高效性和实时性。
支持复杂查询的预算:对于带有积分和聚合操作的复杂查询,物化视图可以显著提高性能。
更简单的管理方式:通过一套简单的命令,创建和维护物化视图,构造操作涉及深。
3. 创建物化视图在 Doris 中,创建物化视图的基本语法如下:
12345CREATE MATERIALIZED VIEW mv_nameASSELECT <column_list>FROM ...
Closeable接口
Closeable通常来说,Closeable接口的使用需要配合 try with resource,关闭时自动执行Closeable接口定义的 close 方法
如果没有实现这个接口,就无法使用 try with resource,且需要手动关闭资源
永不放弃——特朗普自述 NEVER GIVE UP
永不放弃——特朗普自述【笔记整理】
关注解决之道,而不要抱怨出现的问题。
你的生意做的越大,你的人生境界越高,那么你遭遇的困难也会越有挑战性。如果你有这样的思想准备,那么在遇到困难时自己的情绪波动就不会太大,也不会无谓地烦恼甚至积郁成疾。
如果你觉得一个人在苦苦打拼,那么你可以用这种积极的精神力量来鼓励自己,内在的信念往往是人们分出伯仲高下的隐性分水岭。失败者往往都会选择放弃。
如果你遇到需要让你投入更多时间的情形,你不妨尝试一下,让自己渐入佳境。你最后都会为自己每天的成就而感到惊讶。
有的时候,如果你把所有可能出现的问题都考虑到了之后,你就不妨可以去想象可能会出现什么好事了。
勇气意味着绝不放弃。背弃理想很容易,失败者往往就是缩手缩脚的。被打倒是一回事,而自暴自弃则是另一回事。一些看似平凡的人之所以能够创下丰功伟业,正是因为他们的百折不挠和永不放弃的精神。
海明威说过一句名言:“勇气就是优雅地面对压力。”
勇气还有另一个好处,那就是能够帮助你用正确的思维来考虑问题和做出行动,它会让你关注面前的机遇,而非障碍。其实,很多问题换个角度去考虑就是机遇,只不过它的表现形式让我们 ...
SQL必知必会-读书笔记(十三)
SQL必知必会-读书笔记(十三)存储过程是什么存储过程(Stored Procedure) 是一组预编译的SQL语句,它们被存储在数据库中,可以像函数一样被调用。存储过程可以接受输入参数、输出参数,并且可以包含控制流语句(如条件判断、循环等)。存储过程的主要目的是提高数据库操作的效率和安全性,减少网络流量,并且可以封装复杂的业务逻辑。
优点
提高性能:存储过程在创建时会被编译并存储在数据库中,执行时不需要再次编译,提高了执行效率。
减少网络流量:客户端只需要发送存储过程的调用请求,而不需要发送大量的SQL语句,减少了网络传输的数据量。
封装业务逻辑:存储过程可以封装复杂的业务逻辑,使应用程序代码更加简洁。
提高安全性:通过授予用户对存储过程的执行权限,可以限制用户直接访问底层表,提高数据的安全性。
虽然实践中基本用不到存储过程,但是可以作为了解的一环
如何创建基本语法
123456789DELIMITER //CREATE PROCEDURE procedure_name (IN param1 datatype, OUT param2 datatype)BEGIN -- S ...
SQL必知必会-读书笔记(十二)
SQL必知必会-读书笔记(十二)关于更新和删除
使用 UPDATE 时,只需要写一个 SET
如果想要更快地删除,可以使用 TRUNCATE TABLE,因为该命令不记录数据的变动
关于视图是什么视图是虚拟的表,只包含使用时动态检索数据的查询。
关键点视图本身不能加索引,但视图内sql的执行有可能会走索引
我理解的视图更多地用于逻辑封装,提高可读性,在追求速度和效率的场景中,暂时不了解视图带来的优势
总结视图的优点
简化查询和提高可维护性:视图可以封装复杂的查询逻辑,使查询更简单和易于维护。
视图的缺点
可能增加性能开销:视图在每次查询时都会重新执行其定义的查询,可能导致额外的性能开销,特别是在涉及大量数据或复杂查询时。
SQL必知必会-读书笔记(十一)
SQL必知必会-读书笔记(十一)在 MySQL 中,INSERT 语句可以使用 SELECT 子句来插入数据,但并不是所有的 SELECT 选项都可以直接用于 INSERT ... SELECT 语句中。以下是一些常见的 SELECT 选项及其在 INSERT ... SELECT 语句中的适用性:
可以使用的 SELECT 选项
基本 SELECT 子句:
1234INSERT INTO target_table (column1, column2, column3)SELECT column1, column2, column3FROM source_tableWHERE condition;
JOIN 操作:
12345INSERT INTO target_table (column1, column2, column3)SELECT t1.column1, t1.column2, t2.column3FROM table1 t1JOIN table2 t2 ON t1.id = t2.idWHERE condition;
聚合函数:
1234INSERT INTO ta ...
SQL必知必会-读书笔记(十)
SQL必知必会-读书笔记(十)UNION性能问题多数DBMS内部会使用查询优化程序,理论上讲,相同含义的UNION和多条WHERE子句在性能上应该没有实际的差别,但实践上,查询程序并不能达到理想状态,实践中,可以通过测试两种方法工作效果更好。
UNION规则
每个子查询都需要 UNION 连接
每个子查询必须都有相同数量的列、表达式或聚集函数(不过各个列不需要以相同的次序出现)
列数据类型必须兼容,但不必完全相同,满足隐式转换条件即可
如果遇到不同列名时会发上什么?
MySQL会采用第一个结果集的列名,因此,如果想要排序,也只能使用第一个字查询的别名进行排序,否则会报错
UNION 和 UNION ALL
UNION总是完成与多个WHERE条件相同的工作,为此,UNION 的查询结果是自动去重的
如果希望所有字查询结果都出现,可以使用 UNION ALL
关于排序UNION 或者 UNION ALL 只能进行一次排序,对整个结果集进行排序,不允许对多个字查询进行 ORDER BY
Integer.valueOf()对比Integer.parseInt()
Java 中 Integer.valueOf() 和 Integer.parseInt() 的区别及实践在 Java 中,处理字符串与整数的转换时,Integer.valueOf() 和 Integer.parseInt() 是最常用的两个方法。
这两个方法虽然看似相似,但在实际使用中却有一些关键的区别。本文将详细讲解这两个方法的用法、内部实现及其不同之处,并结合实际示例来帮助大家更好地理解和使用。
方法定义和基本用法1. Integer.valueOf()方法定义:
12public static Integer valueOf(String s) throws NumberFormatException;public static Integer valueOf(int i);
用法:
Integer.valueOf(String s):将字符串 s 转换为 Integer 对象。
Integer.valueOf(int i):将基本数据类型 int 转换为 Integer 对象。
示例:
12Integer num1 = Integer.valueOf("123 ...
ES 文档基本操作
ES 文档基本操作添加文档模版:
12345678910POST /索引库名/_doc/文档id{ "字段1": "值1", "字段2": "值2", "字段3": { "子属性1": "值3", "子属性1": "值4" } // ......}
如果没有文档id,ES会随机生成一个
示例:
123456789POST /demo_index/_doc/1{ "demo_property_1":"test_content1_text", "demo_property_2":"test_content1_keyword", "demo_property_3":{ "demo_child_property ...
JsonNode API文档
JsonNode API 文档概述JsonNode 是 Jackson 数据绑定库中的一个类,用于表示 JSON 数据的节点。它是 com.fasterxml.jackson.databind.JsonNode 包的一部分,提供了处理 JSON 数据的灵活接口。
主要特性
支持多种类型的 JSON 数据(对象、数组、字符串、数字、布尔值和 null)。
支持树状结构的动态访问和遍历。
提供类型安全的方法访问 JSON 数据。
创建 JsonNode从 JSON 字符串创建1JsonNode jsonNode = objectMapper.readTree("{\"key\":\"value\"}");
从 Java 对象创建1JsonNode jsonNode = objectMapper.valueToTree(yourObject);
主要方法节点类型判断
boolean isObject()检查当前节点是否为 JSON 对象。
boolean isArray()检查当前节点是否为 JSON 数 ...
JsonNode详解
JsonNode 详解com.fasterxml.jackson.databind.JsonNode.JsonNode 是 Jackson 库中表示 JSON 数据结构的核心类之一,属于 com.fasterxml.jackson.databind 包。
它用于以树状结构解析和处理 JSON 数据。
JsonNode 的基本特性
树状结构:JsonNode 可以表示 JSON 的各种类型,包括对象、数组、字符串、数字、布尔值和 null。
动态访问:支持动态访问 JSON 节点的属性和元素,可以方便地进行遍历和操作。
类型安全:虽然 JsonNode 是一个通用类型,但它提供了一些方法以确保对 JSON 数据的类型安全访问。
创建 JsonNodeJsonNode 主要通过 ObjectMapper 类创建。以下是一些常用的方法:
12345678910import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.databind.JsonNode;ObjectMapper object ...
数据库表字符编码utf8和utf8mb4
数据库表编码:UTF-8 与 UTF8MB4 的区别及选择编码概述在数据库中,字符编码定义了如何存储和处理字符串数据。UTF-8 和 UTF8MB4 是 MySQL 中常用的字符编码,具有不同的特性和适用场景。
UTF-8
定义:UTF-8 是一种可变长度字符编码,使用 1 到 4 个字节表示一个字符。
范围:支持 Unicode 字符集的绝大多数字符,但不支持某些特殊字符(如某些表情符号)。
字节限制:在 MySQL 中,UTF-8 仅使用 1 到 3 个字节存储字符。
UTF8MB4
定义:UTF8MB4 是 UTF-8 的扩展,完整支持 Unicode,包括所有字符。
范围:除了基本的多语言字符外,还支持所有的 emoji 和其他非基本字符。
字节限制:使用 1 到 4 个字节表示一个字符。
主要区别
特性
UTF-8
UTF8MB4
最大字节数
3 字节
4 字节
支持的字符范围
不支持某些 emoji
支持所有 Unicode 字符
应用场景
多数语言文本
包含特殊符号、表情符号等的文本
实战中的选择在选择字符编码时,考虑以下因素:
数据类型和内容
...
Spring事务管理的原理
Spring事务管理的原理Spring 通过 AOP 实现声明式事务的机制是其事务管理的核心部分。
声明式事务和编程式事务的实现原理不同。
声明式事务的实现原理AOP(面向切面编程)
代理模式:Spring 使用 AOP 代理模式来实现声明式事务。具体而言,当你在服务方法上使用 @Transactional 注解时,Spring 会生成一个代理对象,该对象会拦截方法调用。
切面:切面是 AOP 的核心概念,包含了切点(定义在哪些方法上应用切面)和通知(在切点方法执行前、后或异常时执行的逻辑)。在事务管理中,切面会处理事务的开启、提交和回滚。
事务通知:当目标方法被调用时,代理会执行事务的前置逻辑(例如开启事务),然后调用目标方法。执行完毕后,代理会根据方法执行的结果(正常结束或抛出异常)决定是否提交或回滚事务。
具体流程
方法调用:
当调用标注了 @Transactional 的方法时,Spring 代理会拦截该调用。
事务开始:
代理会使用配置的事务管理器开始一个新事务。
执行目标方法:
代理调用实际的业务逻辑方法。
事务结束:
根据目标方法的执行结果(正 ...
未检查的异常
未检查的异常未检查的异常(Unchecked Exception)是指在编译时不需要强制捕获或声明的异常。
在 Java 中,未检查的异常是 RuntimeException 类及其子类的实例,以及 Error 类及其子类的实例。
未检查的异常通常表示程序中的逻辑错误或不应当发生的情况。
主要特点
不需要显式处理:编译器不会强制要求在代码中捕获或声明这些异常。开发者可以选择处理这些异常,也可以不处理。
程序逻辑错误:未检查的异常通常表示程序内部的逻辑错误,例如访问数组的非法索引、空指针引用等。它们通常表示错误的程序设计。
运行时异常:未检查的异常通常在程序运行时发生,而不是在编译时。例如:
NullPointerException
ArrayIndexOutOfBoundsException
ClassCastException
事务管理中的应用在 Spring 中,默认情况下,只有未检查的异常(如 RuntimeException)会导致事务回滚。这意味着:
如果方法执行中抛出未检查的异常,Spring 会自动回滚当前事务。
如果方法执行中抛出已检查的异常(如 IOEx ...
\@Value注解缺省值的细节
@Value缺省值的细节使用 @Value 注解时,缺省值的一些细节包括:
格式:在 .properties 文件中,缺省值不需要用单引号包裹;在 YAML 文件中,可以使用单引号。
占位符:可以使用 ${} 来引用其他属性。
默认值语法:可以通过 :${defaultValue} 指定缺省值,例如:${some.property:defaultValue}。
类型转换:Spring 会自动根据目标字段类型进行类型转换。
异常处理:如果没有找到值且没有提供缺省值,可能会抛出异常。
事务传播的概念
事务传播的概念概述
事务传播是指在执行数据库操作时,如何处理当前事务与外部事务之间的关系。
在多层架构或分布式系统中,事务传播机制可以确保数据的一致性和完整性。
Spring 框架提供了多种事务传播行为,帮助开发者灵活管理事务。
事务传播的意义
数据一致性:确保在不同的数据库操作中,数据的一致性得以保持,避免因事务未提交或回滚而导致的数据不一致。
灵活性:允许在不同的业务逻辑层次中定义事务的行为,以便在需要的情况下开启或使用现有的事务。
错误处理:在出现异常时,能够决定是回滚当前事务还是让外部事务负责,从而简化错误处理逻辑。
Spring 中的事务传播行为Spring 提供了七种事务传播行为,分别是:
REQUIRED(默认行为):
如果当前存在事务,则加入该事务;如果不存在事务,则新建一个事务。
适用于大多数场景。
REQUIRES_NEW:
总是新建一个事务,即使当前存在事务也会暂停当前事务。
适用于需要独立事务的场景,如日志记录或审计功能。
NESTED:
如果当前存在事务,则在该事务中嵌套一个事务;如果不存在事务,则新建一个事务。
适用于需要部分 ...
\@ConditionalOnProperty 详解
@ConditionalOnProperty 注解详解概述@ConditionalOnProperty 是 Spring Boot 提供的一个条件注解,用于根据特定的属性值来决定是否加载某个 Spring Bean。
它使得 Bean 的创建变得更加灵活,允许开发者根据配置的不同来控制 Bean 的注册。
作用
灵活配置:可以根据不同的环境或配置条件,选择性地启用或禁用某个 Bean。
提高模块化:使得应用程序能够更好地适应不同的需求,避免了在代码中硬编码条件逻辑。
使用方法基本用法使用 @ConditionalOnProperty 注解时,可以指定以下几个属性:
**value/name**:要检查的属性名(必须是一个属性)。
**havingValue**:当属性值匹配时,条件成立,默认为 true。
**matchIfMissing**:如果指定的属性不存在,是否匹配,默认为 false。
示例假设我们有一个服务类 MyService,我们希望根据配置文件中的属性 app.service.enabled 来决定是否注册该 Bean。
1. 配置文件
在 appli ...
\@ConfigurationProperties 详解
@ConfigurationProperties 注解详解概述@ConfigurationProperties 是 Spring Framework 提供的一个注解,用于将外部配置(如 YAML 或 properties 文件)绑定到 Java 对象。
它主要用于集中管理应用程序的配置,简化了配置项的读取和使用。
作用
简化配置管理:将多个相关的配置项聚合到一个类中,便于管理和使用。
类型安全:通过强类型的 Java 对象来获取配置,避免了使用字符串常量,减少了出错的可能性。
便于测试:将配置与业务逻辑分离,使得测试变得更加简单。
使用方法添加依赖确保在 pom.xml 中添加 Spring Boot Starter:
1234<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId></dependency>
创建配置类创建一个类并使用 @Configur ...
为什么Servlet规范规定了只能调用一次getReader方法
为什么一个 Servlet 只能调用一次 getReader() 方法在 Java EE 的 Servlet 规范中,HttpServletRequest 接口的 getReader() 方法用于获取请求体的字符输入流。
然而,一个 Servlet 只能调用一次 getReader() 方法,原因如下:
输入流的单次消费特性
流的性质:输入流(如 BufferedReader)的设计目的是一次性读取数据。读取操作会消耗流中的数据,改变流的状态。调用 getReader() 后,请求体的内容被读取,后续的读取请求会发现流已被关闭或数据已被消费。
设计决策:这种设计确保了输入流的简单性和高效性,避免了复杂的状态管理。它使得开发者在处理请求体时,不必担心流的状态管理和重置。
资源管理
内存和性能:请求体可能很大,尤其在上传文件或大文本数据时。允许多次读取将导致额外的内存开销和性能损失,可能会导致应用程序崩溃或响应缓慢。
避免泄漏:如果允许多个读取,开发者需要显式管理流的生命周期,增加了出错的可能性,如未能正确关闭流,导致内存泄漏。
保持请求的一致性
数据一致性:如果允许多次读取同一请求体 ...
OOD五大原则SOLID总览
OOD五大原则SOLID总览SOLID 是面向对象设计的五大基本原则的首字母缩写,旨在帮助开发者编写更清晰、灵活和易于维护的代码。
它们有助于设计可扩展和可维护的系统,特别是在复杂的项目中应用非常广泛。
详解介绍见链接:
SOLID
LINK
SRP
单一职责原则
OCP
开放封闭原则
LSP
里氏替换原则
ISP
接口隔离原则
DIP
依赖倒置原则
以下是五大 SOLID 原则的简单介绍:
1. 单一职责原则 (Single Responsibility Principle, SRP)定义:每个类应该只有一个职责,即只做一件事。简单来说,一个类应该只有一个引起其变化的原因。
目的:
降低类的复杂度。
提高类的可读性和可维护性。
使代码更容易修改,减少因为一个改动影响到不相关的功能。
示例:12345678910111213141516171819class User { private String name; private String email; // 只处理用户信息 public void updateN ...
接口隔离原则ISP
接口隔离原则 (Interface Segregation Principle, ISP)ISP 是五大 SOLID 原则中的重要组成部分。它们的目标是通过合理的设计和架构,提升系统的可维护性、扩展性和灵活性。
定义接口隔离原则(Interface Segregation Principle, ISP)规定:客户端不应该被强迫依赖它们不需要的接口。
也就是说,一个接口不应包含过多与客户端无关的方法,而应该根据不同的功能需求,将接口细化为多个具体的接口,以避免冗余和依赖过多不必要的方法。
在设计接口时,ISP 提倡将大而全的接口拆分成多个小而精的接口,每个接口只服务于特定的子功能。
这样,类只会实现自己需要的接口,避免了依赖不必要的接口或方法,从而减少耦合性。
为什么需要接口隔离原则?
减少类与接口的耦合:如果类实现了不相关的方法,会引入不必要的依赖,使代码变得复杂且难以维护。
提高灵活性:细化的接口使类可以根据需要实现相关功能,不受其他不相关功能的影响。
提高系统可维护性:接口更精细、更清晰,使得代码的理解和维护变得更容易。
减少冗余:避免了一个类不得不实现与自己无关的功能,简化了类 ...
开放封闭原则OCP
开放封闭原则 (Open-Closed Principle, OCP)DIP 是五大 SOLID 原则中的重要组成部分。它们的目标是通过合理的设计和架构,提升系统的可维护性、扩展性和灵活性。
定义开放封闭原则(Open-Closed Principle, OCP)规定:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。
也就是说,在不修改现有代码的情况下,通过扩展功能来满足新的需求。
这一原则要求开发者在设计系统时,要确保系统能够适应不断变化的需求,同时尽量避免直接修改已经存在的代码。
通过扩展而非修改来添加新功能,可以减少对现有系统的影响,降低出错的可能性,并提高系统的稳定性和可维护性。
为什么需要开放封闭原则?
减少修改的风险:直接修改已有代码,可能会引发新的错误。开放封闭原则通过扩展功能避免了修改现有代码的风险。
提高代码的灵活性:通过扩展功能,可以轻松地适应需求的变化,而无需触碰核心代码。
支持代码复用:OCP 鼓励通过继承或组合的方式来扩展已有功能,这使得系统中的不同模块能够重复使用现有的代码。
提升代码的可维护性:对修改的封闭意味着代码的稳定性得到了增强,使得维护变 ...
单一职责原则SRP
单一职责原则 (Single Responsibility Principle, SRP)SRP 是五大 SOLID 原则中的重要组成部分。它们的目标是通过合理的设计和架构,提升系统的可维护性、扩展性和灵活性。
定义单一职责原则(Single Responsibility Principle, SRP)规定:一个类应该只有一个引起其变化的原因。
换句话说,一个类应该只负责一件事情,具有单一职责。
在面向对象设计中,SRP 强调类的职责单一性,以减少类的复杂性和提高其可维护性。
如果一个类承担了多个职责,那么当其中一个职责发生变化时,这个类就需要修改。过多的职责会让类变得臃肿且难以维护,增加代码出错的风险。
原理SRP 背后的逻辑是:任何一个类都应该只负责一项功能,这使得类的结构更加简单且易于理解。
当系统功能发生变化时,只需要修改特定职责的类,而不会影响其他无关功能的代码。
为什么需要单一职责原则?
降低耦合:类的每一项职责都可能与其他系统部分发生交互。职责越多,耦合性越高。
提高可维护性:当某个职责发生变化时,SRP 确保只需要修改相关的类,降低出错的风险。
简化测试:职责单一的类 ...
依赖倒置原则DIP
依赖倒置原则 (Dependency Inversion Principle, DIP)DIP 是五大 SOLID 原则中的重要组成部分。它们的目标是通过合理的设计和架构,提升系统的可维护性、扩展性和灵活性。
定义依赖倒置原则的核心思想是:高层模块不应该依赖低层模块,二者都应该依赖于抽象。
也就是说,具体的实现类应该依赖于接口或抽象类,而不是高层模块直接依赖实现细节。
依赖倒置原则常常用于创建解耦的系统,减少代码模块之间的直接依赖性。
主要内容
高层模块(如业务逻辑层)不应该依赖低层模块(如数据访问层),二者应该依赖于接口或抽象类。
抽象不应该依赖具体实现,而具体实现应该依赖于抽象。
好处
增强灵活性:代码依赖于接口或抽象类,便于更换不同的实现,而不需要修改高层模块的代码。
解耦模块:高层模块和低层模块通过抽象层进行交互,降低了耦合度,便于维护和扩展。
可扩展性强:添加新的实现类时,不需要改变原有的高层模块,只需实现接口或继承抽象类即可。
示例代码1234567891011121314151617181920212223242526272829303132333435// 抽象层 ...
里氏替换原则LSP
里氏替换原则 (Liskov Substitution Principle, LSP)LSP 是五大 SOLID 原则中的重要组成部分。它们的目标是通过合理的设计和架构,提升系统的可维护性、扩展性和灵活性。
定义里氏替换原则的核心思想是:子类对象必须能够替换其父类对象,并且不会影响程序的正确性。
这意味着子类在扩展父类的功能时,不能改变父类原有的行为。
简单来说,程序中的子类对象应该能在任何父类对象可以出现的地方正常工作。
主要内容
子类应该完全兼容父类,任何使用父类的地方都可以安全地使用子类。
子类在重写父类方法时,不能违反父类的方法行为规范。
子类在继承父类的同时,不应该对父类的功能做破坏性的修改。
好处
增强系统的灵活性:符合 LSP 的子类能够无缝替换父类,使得代码更易于扩展和维护。
提高代码的健壮性:确保子类在继承父类时,不会破坏程序的行为,使得程序更加稳定和可靠。
减少继承带来的副作用:如果子类修改了父类的核心逻辑,可能会带来意料之外的问题。LSP 的遵守可以减少这种副作用。
示例代码123456789101112131415161718192021222324252 ...
Maps.newHashMapWithExpectedSize
Maps.newHashMapWithExpectedSizeMaps.newHashMapWithExpectedSize 是 Guava 库中的一个静态方法
用于创建一个具有预期大小的 HashMap。它通过合理地预估所需的容量,减少 HashMap 在扩容时的开销,从而提升性能。
方法签名1public static <K, V> HashMap<K, V> newHashMapWithExpectedSize(int expectedSize)
参数
expectedSize:预期 HashMap 的大小,也就是你打算存入的键值对数量。此方法会根据这个值来计算合适的初始容量,以尽量减少扩容操作。
关键点:是预期键值对的大小,不是预期容器大小!,实际容量是 expectedSzie ÷ (3/4) 向 2^n 向上取值
返回值
返回一个初始化好的 HashMap<K, V> 对象,其容量已经根据传入的 expectedSize 进行了优化。
重要说明:
容量与负载因子:HashMap 默认的负载因子是 0.75,也就是说,当 ...
ES object与nested
ES object与nested在 ES 中,object 和 nested 是用来表示复杂 JSON 结构的两种字段类型
object 类型object 类型是最基本的嵌套结构,用来表示 JSON 对象中的字段。这些字段会被扁平化存储在同一个文档中。
使用场景
当你需要存储一个简单的对象或键值对,并且不需要在查询时进行复杂的关联操作。
适合处理非数组的嵌套结构,或者数组中的元素之间不需要保持独立的关联。
定义方式123456789101112131415161718PUT /my_index{ "mappings": { "properties": { "user": { "type": "object", "properties": { "first_name": { "type" ...
索引库基本操作
索引库基本操作ES 通过 Restful 请求操作索引库、文档,本文介绍如何使用 DSL 来操作索引库
创建索引库示例模版
12345678910111213141516171819202122232425PUT /索引库名称{ "mappings":{ "properties":{ "字段1":{ "type":"text", "analyzer":"ik_smart" }, "字段2":{ "type":"keyword", "index":"false" }, "字段3":{ "properties" ...
索引库-mapping
索引库-mapping写在前面的话:
在 Elasticsearch 6.x 及之前,每个索引中可以包含多个“类型”(类似于 SQL 中的表),通过类型区分不同文档结构。
从 Elasticsearch 7.x 开始,移除了类型的概念,所有文档在一个索引中共享相同的映射(mapping)。也就是说,不能再通过 type 区分不同文档,而是直接使用索引级别的映射。
Elasticsearch 8.x 彻底移除了类型字段,即 _type 字段完全不存在。
在 Elasticsearch 7.x 及以上版本中,索引结构的基础已经从原来的“类型(type)”转变为纯粹基于文档和字段(document and field)。
mapping 是对索引库中 document 的约束,本文介绍常见的mapping属性
常见的mapping属性
type(字段类型)
index(是否创建索引,默认true)
analyzer(分词器)
properties(该字段有哪些子字段)
type 类型详解核心数据类型文本类型 text文本类型默认会被分词,可以指定 index:"fal ...
IK分词器的扩展与停用词典
IK分词器的扩展与停用词典什么是扩展词典/停用词典可以通过编辑扩展词典和停用词典来改变分词规则
扩展词典:有些词并不是关键词,但是也希望被ES用来作为检索的关键词,可以将这些词加入扩展词典。
停用词典 有些词是关键词,但是出于业务场景不想使用这些关键词被检索到,可以将这些词放入停用词典。
如何添加扩展词典和停用词典?所在目录:
编辑 IKAnalyzer.cfg.xml 文件
1234567891011121314<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"><properties> <comment>IK Analyzer 扩展配置</comment> <!--用户可以在这里配置自己的扩展字典 --> <entry key="ext_dict" ...
docker安装ES kibana ik
docker安装ES kibana ikStep 1. 创建 Docker 网络1docker network create elastic-network
Step 2. 创建Docker Compose 文件在一个目录下创建一个名为 docker-compose.yml 的文件,内容如下:
12345678910111213141516171819202122232425262728293031323334353637383940version: '3'services: elasticsearch: image: elasticsearch:7.17.0 container_name: elasticsearch environment: - discovery.type=single-node - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - cluster.name=docker-cluster - node.name=node-1 - ne ...
