代码 Review 检查清单-安全 - 性能 - 可读性分维度_第1页
代码 Review 检查清单-安全 - 性能 - 可读性分维度_第2页
代码 Review 检查清单-安全 - 性能 - 可读性分维度_第3页
代码 Review 检查清单-安全 - 性能 - 可读性分维度_第4页
代码 Review 检查清单-安全 - 性能 - 可读性分维度_第5页
已阅读5页,还剩77页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

代码Review检查清单

安全·性能·可读性分维度

从审查理念到工具链的完整实践手册

10大章节·200+检查项·60+代码示例

工程质量实战系列

目录

第一章代码审查的核心理念与价值

第二章代码审查流程与团队协作

第三章安全维度审查清单

第四章性能维度审查清单

第五章可读性维度审查清单

第六章分语言特定检查清单

第七章自动化工具链建设

第八章审查沟通与反馈技巧

第九章实战案例与常见反模式

第十章检查清单速查表与模板

代码Review检查清单·安全/性能/可读性分维度

第一章代码审查的核心理念与价值

1.1代码审查的本质

代码审查(CodeReview)是软件开发过程中最重要的质量保障环节之一。它不仅仅是"检查代码有没有bug",

更是一次知识共享、设计探讨和风险识别。一次高质量的代码审查,能在代码合入主干之前,发现安全漏洞、性能

隐患、设计缺陷和可维护性问题,避免这些问题流入生产环境造成更大的代价。

代码审查的核心价值可以归纳为三个方面。质量保障:在代码合入前发现问题,修复成本远低于生产环境出问

题后的代价。知识传递:审查过程中,团队成员相互学习代码风格、设计思路和业务背景。标准统一:通过审查形

成团队共识,逐步沉淀为编码规范,让代码风格趋于一致。

但代码审查也容易陷入误区。最常见的是把审查当成"挑刺",让作者和审查者形成对立关系。正确的理念是:

审查的对象是代码,不是人。审查者提出的是改进建议,作者可以选择接受或讨论。审查的目标是让代码更好,

不是证明谁更聪明。

1.2代码审查的三个层次

层次关注点典型问题审查时间占比

正确性代码能否正确实现功能逻辑错误、边界条件、并发问题30%

质量代码是否安全、高效、易维护安全漏洞、性能隐患、可读性差50%

设计设计是否合理、可扩展职责不清、耦合过重、抽象不当20%

三个层次并非孤立的。正确性是基础,质量是关键,设计是长远。一次好的审查应该覆盖三个层次,但要根据

代码的重要程度和风险等级,合理分配审查精力。

1.3为什么要分维度审查

代码审查容易"顾此失彼"。审查者关注逻辑是否正确时,可能忽略了安全问题;关注性能时,可能忽略了可读

性。分维度审查把审查目标拆解为独立的维度,每个维度有明确的检查清单,能显著降低遗漏概率。

本手册采用三个核心维度:安全维度关注代码是否存在安全漏洞、敏感信息泄露、权限控制不当等问题;性能

维度关注代码是否存在性能瓶颈、资源浪费、算法复杂度问题;可读性维度关注代码是否清晰易懂、命名规范、注

释充分、易于维护。

分维度审查的实践建议:对于小改动(<50行),可以一次性审查三个维度;对于中等改动(50-500行),

建议按维度分别审查;对于大改动(>500行),建议拆分成多个小的PR,每个PR聚焦一个维度。不要让审查

者的注意力被分散到太多不同的问题类型上。

1.4代码审查的ROI分析

代码审查需要投入时间,团队规模越大,审查成本越高。但如果从ROI角度看,代码审查的收益远大于成本。

问题发现阶段修复成本倍数说明

需求设计阶段1x修改文档即可

代码编写阶段5x修改代码、重新测试

代码审查阶段10x需要讨论、重新审查

测试阶段20x定位问题、重新测试

生产环境100x紧急修复、回滚、影响用户

这个倍数关系说明:问题发现得越早,修复成本越低。代码审查是在代码合入主干前发现问题的最后机会,是

性价比最高的质量保障手段之一。

1.5代码审查的反模式

反模式一:橡皮图章。审查者只看代码格式,不深入理解逻辑,草草点"批准"。这种审查毫无价值,反而给

作者虚假的安全感。

反模式二:过度审查。审查者事无巨细地挑出每一个小问题,让作者反复修改,审查周期过长,影响交付效

率。

反模式三:人情审查。因为是熟人、领导或资深同事的代码,就不敢提出问题,睁一只眼闭一只眼。

反模式四:找茬审查。审查者带着情绪,针对个人而非代码,容易引发团队矛盾。

反模式五:一次性大审查。把几个月的代码一次性提交审查,审查者无法深入理解,只能走马观花。

健康的审查文化:审查是团队活动,不是个人对抗。作者应该主动请求审查,欢迎反馈;审查者应该以帮助

作者为目标,语气友好、就事论事。审查意见应该区分"必须修复"和"建议改进",让作者清楚哪些是阻塞问

题,哪些是可选优化。

第二章代码审查流程与团队协作

2.1标准审查流程

代码审查标准流程:

第1步:作者自查

-本地运行测试,确保通过

-检查代码格式,符合规范

-阅读自己的代码,发现明显问题

-撰写清晰的PR描述

第2步:提交PR/MR

-小步提交,单个PR不超过500行

-关联需求或问题单

-补充必要截图或演示

-指定审查者

第3步:自动化检查(CI)

-代码风格检查(ESLint/Checkstyle)

-静态分析(SonarQube/CodeQL)

-单元测试

-构建验证

第4步:人工审查

-审查者阅读代码

-提出问题或建议

-作者回复或修改

-达成一致后批准

第5步:合入主干

-删除源分支

-触发部署流水线

-关闭关联的issue

第6步:事后复盘

-记录常见问题

-更新审查清单

-分享经验教训

2.2PR描述规范

一份好的PR描述能显著降低审查者的认知负担,让审查更快、更准确。PR描述应该包含以下要素。

要素说明示例

变更目的为什么做这个变更修复用户订单查询超时问题

变更内容做了什么修改为order_info表添加联合索引

影响范围会影响哪些功能影响订单查询接口,其他接口无影响

测试方式如何验证改动本地压测,P99从800ms降到50ms

风险提示可能的风险点索引创建期间有短暂锁表,建议低峰执行

关联信息相关issue、文档Fixes#1234

#PR描述模板

##变更目的

修复订单列表页在用户订单数超过1000时查询超时的问题。

##变更内容

1.为`order_info`表添加`idx_user_status_created`联合索引

2.优化订单查询SQL,避免全表扫描

3.添加慢查询监控

##影响范围

-影响接口:`GET/api/v1/orders`

-数据变更:新增索引

-兼容性:完全兼容

##测试方式

-本地环境:10万订单数据,P99从800ms降到50ms

-预发环境:全量数据回归测试通过

-单元测试:全部通过

##风险提示

-索引创建时对现有写入有短暂影响,建议低峰执行

-索引占用约500MB磁盘空间

-回滚方案:DROPINDEX即可

##关联信息

-Issue:#1234

-设计文档:[链接]

-监控面板:[链接]

2.3审查粒度控制

PR规模代码行数审查时长问题发现率

极小<50行5-10分钟高

小50-200行15-30分钟高

中200-500行30-60分钟中

大500-1000行1-2小时中低

超大>1000行>2小时低

研究表明,单次审查超过400行代码时,问题发现率显著下降。超过1000行时,审查者往往只能走马观花,只

能发现表面的问题。因此,推荐单个PR的代码量控制在400行以内。如果变更确实很大,应该拆分为多个小的

PR,每个PR聚焦一个独立的功能点。

2.4审查者的选择

角色职责人数

主要审查者深入审查代码,负责最终批准1人

次要审查者从不同角度提出意见1-2人

领域专家涉及特定领域时参与按需

安全审查者涉及敏感操作时参与按需

审查者的选择要考虑三个因素:熟悉度(对代码涉及的模块有了解)、能力匹配(具备所需的技能和知识)、

独立性(不能是同一人既写又审)。同时要避免审查者过于集中,让团队成员轮流参与,促进知识扩散。

2.5审查时间管理

代码审查的时间分配建议:

【审查前】

-了解变更背景:5分钟

-阅读PR描述:2分钟

-查看关联的issue:3分钟

【审查中】

-通读代码全貌:10%时间

-逐文件深入:70%时间

-记录问题和建议:15%时间

-复查关键点:5%时间

【审查后】

-撰写反馈:10分钟

-跟进作者回复:按需

-最终确认:5分钟

【时间红线】

-单次审查不超过60分钟

-超过60分钟应休息或拆分会话

-不要在疲劳时审查关键代码

-不要在临近下班时审查

【响应时间】

-小PR:24小时内响应

-中PR:48小时内响应

-大PR:72小时内响应

-紧急修复:2小时内响应

2.6团队协作规范

所有代码必须经过审查才能合入主干,没有例外

作者应该主动请求审查,而不是被动等待

审查者应该在SLA内响应,避免阻塞作者

讨论应该聚焦代码,不针对个人

异议时先沟通,达成一致后再修改

重要变更应该有多人审查

审查意见应该明确"必须修改"和"建议优化"

审查中发现的共性问题应该沉淀到规范

定期回顾审查过程,优化流程

新人应该先参与小PR的审查,逐步提升

第三章安全维度审查清单

3.1输入验证与数据校验

所有外部输入都是不可信的。输入验证是安全防线的第一道关卡,任何来自用户、第三方系统、文件、网络的

输入都必须经过严格校验。

检查项说明风险等级

所有输入是否校验?包括参数、路径、Header、Body高

是否校验数据类型?数字、字符串、布尔值等类型匹配高

是否校验长度?最小长度、最大长度高

是否校验范围?数值范围、日期范围高

是否校验格式?正则表达式校验高

是否使用白名单?只允许已知合法值,而非黑名单高

是否处理边界情况?空值、null、0、负数、超长高

//❌危险:直接使用未校验的输入

@PostMapping("/users")

publicUsercreateUser(@RequestBodyUserRequestrequest){

returnuserService.create(request);

}

//✅安全:使用校验注解

publicclassUserRequest{

@NotBlank(message="用户名不能为空")

@Size(min=4,max=32,message="用户名长度4-32")

@Pattern(regexp="^[a-zA-Z0-9_]+$",message="用户名只能包含字母、数字、下划线")

privateStringusername;

@NotBlank(message="邮箱不能为空")

@Email(message="邮箱格式不正确")

privateStringemail;

@NotNull(message="年龄不能为空")

@Min(value=18,message="年龄不能小于18")

@Max(value=120,message="年龄不能大于120")

privateIntegerage;

@NotBlank(message="手机号不能为空")

@Pattern(regexp="^1[3-9]\\d{9}$",message="手机号格式不正确")

privateStringphone;

}

@PostMapping("/users")

publicUsercreateUser(@Valid@RequestBodyUserRequestrequest){

returnuserService.create(request);

}

//✅额外的服务层校验

publicUsercreate(UserRequestrequest){

//二次校验(防止绕过Controller直接调用)

validateRequest(request);

//业务校验

if(userRepository.existsByUsername(request.getUsername())){

thrownewBusinessException("用户名已存在");

}

returnuserRepository.save(convert(request));

}

输入验证的常见错误:第一,只在前端校验,绕过前端就能提交非法数据;第二,使用黑名单而非白名单,

永远存在遗漏;第三,只在Controller校验,Service层没校验;第四,校验后直接使用,未考虑编码问题;第

五,忽略边界值,如空字符串、null、超长输入。

3.2注入攻击防护

//==========SQL注入==========

//❌危险:字符串拼接

Stringsql="SELECT*FROMusersWHEREusername='"

+username+"'ANDpassword='"+password+"'";

Statementstmt=connection.createStatement();

ResultSetrs=stmt.executeQuery(sql);

//攻击输入:

//username="admin'--"

//实际执行的SQL:

//SELECT*FROMusersWHEREusername='admin'--'ANDpassword='...'

//✅安全:使用参数化查询

Stringsql="SELECT*FROMusersWHEREusername=?ANDpassword=?";

PreparedStatementstmt=connection.prepareStatement(sql);

stmt.setString(1,username);

stmt.setString(2,password);

//✅安全:使用ORM

Useruser=userRepository.findByUsernameAndPassword(username,password);

//✅安全:使用MyBatis参数化

//@Select("SELECT*FROMusersWHEREusername=#{username}")

//UserfindByUsername(@Param("username")Stringusername);

//❌危险:MyBatis使用${}

//@Select("SELECT*FROMusersWHEREusername='${username}'")

//==========命令注入==========

//❌危险:直接拼接命令

Stringcmd="ping"+userInput;

Runtime.getRuntime().exec(cmd);

//攻击输入:userInput=";rm-rf/"

//✅安全:使用参数数组

ProcessBuilderpb=newProcessBuilder("ping","-c","1",userInput);

//或使用白名单校验

if(!userInput.matches("^[0-9.]+$")){

thrownewIllegalArgumentException("非法输入");

}

//==========路径穿越==========

//❌危险:直接使用用户提供的文件名

StringfileName=request.getParameter("file");

Filefile=newFile("/data/uploads/"+fileName);

//攻击输入:fileName="../../etc/passwd"

//✅安全:校验文件名

StringfileName=request.getParameter("file");

if(fileName.contains("..")||fileName.contains("/")||fileName.contains("\\")){

thrownewIllegalArgumentException("非法文件名");

}

//更好的方案:使用白名单+规范化

PathbasePath=Paths.get("/data/uploads").toRealPath();

PathfilePath=basePath.resolve(fileName).toRealPath();

if(!filePath.startsWith(basePath)){

thrownewIllegalArgumentException("非法路径");

}

//==========XSS(跨站脚本)==========

//❌危险:直接输出用户输入

//

//

//✅安全:HTML转义

//

//输出:<script>alert(document.cookie)</script>

//✅前端富文本:使用专业的HTML清洗库

importorg.owasp.html.HtmlPolicyBuilder;

importorg.owasp.html.PolicyFactory;

PolicyFactorypolicy=newHtmlPolicyBuilder()

.allowElements("p","br","strong","em","a")

.allowUrlProtocols("https")

.allowAttributes("href").onElements("a")

.toFactory();

StringsafeHtml=policy.sanitize(userContent);

3.3认证与授权

检查项说明风险等级

密码是否加密存储?使用bcrypt、argon2,绝不明文极高

是否使用强密码策略?长度、复杂度要求高

是否支持MFA?敏感操作需要二次认证中高

会话是否安全?HttpOnly、Secure、SameSite高

Token是否过期?设置合理的过期时间高

是否防止暴力破解?限流、验证码、账户锁定高

权限是否最小化?只授予必要的权限高

是否防越权?水平越权、垂直越权极高

//❌危险:明文存储密码

user.setPassword(password);

userRepository.save(user);

//✅安全:使用bcrypt哈希

importorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

BCryptPasswordEncoderencoder=newBCryptPasswordEncoder(12);

user.setPassword(encoder.encode(password));

userRepository.save(user);

//验证密码

if(encoder.matches(rawPassword,user.getPassword())){

//认证成功

}

//❌危险:水平越权

@GetMapping("/orders/{orderId}")

publicOrdergetOrder(@PathVariableLongorderId){

returnorderService.getById(orderId);

}

//任何登录用户都能查看别人的订单

//✅安全:校验归属

@GetMapping("/orders/{orderId}")

publicOrdergetOrder(@PathVariableLongorderId,

@AuthenticationPrincipalUserPrincipalprincipal){

Orderorder=orderService.getById(orderId);

if(order==null){

thrownewNotFoundException();

}

if(!order.getUserId().equals(principal.getId())){

thrownewAccessDeniedException("无权访问此订单");

}

returnorder;

}

//✅使用注解式权限

@PreAuthorize("#orderId==authentication.principal.userIdorhasRole('ADMIN')")

@GetMapping("/orders/{orderId}")

publicOrdergetOrder(@PathVariableLongorderId){

returnorderService.getById(orderId);

}

//❌危险:垂直越权

@DeleteMapping("/users/{userId}")

publicvoiddeleteUser(@PathVariableLonguserId){

userService.delete(userId);

}

//普通用户也能删除其他用户

//✅安全:使用角色权限

@PreAuthorize("hasRole('ADMIN')")

@DeleteMapping("/users/{userId}")

publicvoiddeleteUser(@PathVariableLonguserId){

userService.delete(userId);

}

3.4敏感数据处理

//==========敏感信息不应出现在日志中==========

//❌危险:打印敏感信息

("用户登录,用户名:{},密码:{}",username,password);

("支付成功,卡号:{}",cardNumber);

("请求参数:{}",JSON.toJSONString(request));

//✅安全:脱敏后打印

("用户登录,用户名:{}",mask(username));

("支付成功,卡号:{}",maskCardNumber(cardNumber));

("请求参数:{}",JSON.toJSONString(sanitize(request)));

//==========敏感信息加密存储==========

//❌危险:明文存储

CREATETABLEuser_bank_card(

idBIGINTPRIMARYKEY,

card_numberVARCHAR(32)NOTNULL,

cvvVARCHAR(4)NOTNULL

);

//✅安全:加密存储

CREATETABLEuser_bank_card(

idBIGINTPRIMARYKEY,

card_number_encryptedVARBINARY(256)NOTNULL,

card_number_hashCHAR(64)NOTNULL,--用于查询

card_last4CHAR(4)NOTNULL,--用于展示

created_atDATETIMENOTNULL,

KEYidx_card_hash(card_number_hash)

);

//加密实现

publicclassCardService{

privatestaticfinalStringALGORITHM="AES/GCM/NoPadding";

privatefinalSecretKeykey;

publicStringencryptCardNumber(StringcardNumber){

Ciphercipher=Cipher.getInstance(ALGORITHM);

byte[]iv=generateIv();

cipher.init(Cipher.ENCRYPT_MODE,key,newGCMParameterSpec(128,iv));

byte[]encrypted=cipher.doFinal(cardNumber.getBytes());

returnBase64.getEncoder().encodeToString(

ByteBuffer.allocate(iv.length+encrypted.length)

.put(iv).put(encrypted).array()

);

}

publicStringhashCardNumber(StringcardNumber){

//使用加盐哈希,防止彩虹表

returnDigestUtils.sha256Hex(cardNumber+SALT);

}

}

//==========响应中脱敏==========

publicclassUserVO{

privateLongid;

privateStringusername;

privateStringemail;

@JsonProperty("phone")

privateStringmaskedPhone;

@JsonProperty("id_card")

privateStringmaskedIdCard;

}

publicUserVOconvert(Useruser){

UserVOvo=newUserVO();

vo.setId(user.getId());

vo.setUsername(user.getUsername());

vo.setEmail(maskEmail(user.getEmail()));

vo.setMaskedPhone(maskPhone(user.getPhone()));

vo.setMaskedIdCard(maskIdCard(user.getIdCard()));

returnvo;

}

privateStringmaskPhone(Stringphone){

if(phone==null||phone.length()<11)returnphone;

returnphone.substring(0,3)+"****"+phone.substring(7);

}

privateStringmaskIdCard(StringidCard){

if(idCard==null||idCard.length()<18)returnidCard;

returnidCard.substring(0,6)+"********"

+idCard.substring(idCard.length()-4);

}

3.5依赖与配置安全

检查项说明风险等级

依赖是否有已知漏洞?使用SCA工具扫描高

依赖版本是否锁定?使用lock文件锁定版本中高

是否使用官方源?避免使用不可信的仓库中

配置中的密钥是否安全?使用环境变量或密钥管理服务极高

调试配置是否禁用?生产环境禁用debug模式高

错误信息是否泄露内部信息?生产环境不返回堆栈中高

#依赖漏洞检查工具

#Java:OWASPDependency-Check

mvnorg.owasp:dependency-check-maven:check

#Node.js:npmaudit

npmaudit

npmauditfix

#Python:Safety

pipinstallsafety

safetycheck

#通用:Trivy

trivyfs.

#配置中的密钥检查

#❌危险:硬编码密钥

application:

secret-key:"abc123def456ghi789"

#✅安全:使用环境变量

application:

secret-key:${APP_SECRET_KEY}

#✅更好:使用密钥管理服务

@Configuration

publicclassSecretConfig{

@Bean

publicStringsecretKey(){

//从AWSSecretsManager读取

AWSSecretsManagerclient=AWSSecretsManagerClientBuilder.defaultClient();

GetSecretValueRequestrequest=newGetSecretValueRequest()

.withSecretId("prod/app/secret-key");

returnclient.getSecretValue(request).getSecretString();

}

}

3.6安全审查清单汇总

所有外部输入是否经过校验?

是否使用白名单而非黑名单?

SQL查询是否使用参数化?

是否避免命令注入、路径穿越?

输出是否经过HTML转义?

密码是否使用强哈希算法存储?

是否防止水平越权和垂直越权?

敏感数据是否加密存储和传输?

日志中是否避免记录敏感信息?

是否校验文件上传类型和大小?

是否防止CSRF攻击?

是否设置了安全响应头?

依赖是否有已知漏洞?

密钥是否安全存储?

错误信息是否泄露内部结构?

第四章性能维度审查清单

4.1数据库性能审查

数据库性能问题是生产环境中最常见的性能瓶颈。审查时应该重点关注查询效率、索引使用和事务管理。

检查项说明影响

SQL是否使用了索引?EXPLAIN检查执行计划极大

是否避免SELECT*?只查询需要的字段大

是否避免循环中的查询?N+1问题极大

是否避免深分页?LIMIT大偏移量大

是否避免大事务?事务范围要小大

是否使用批量操作?批量插入/更新大

是否有缺失的索引?根据查询模式检查极大

--❌性能问题:SELECT*

SELECT*FROMorder_infoWHEREuser_id=123;

--问题:可能返回大量不需要的字段,包括TEXT、BLOB

--✅优化:明确字段

SELECTid,order_no,status,total_amount,created_at

FROMorder_infoWHEREuser_id=123;

--❌性能问题:循环查询(N+1)

Listorders=orderRepository.findByUserId(userId);

for(Orderorder:orders){

Useruser=userRepository.findById(order.getUserId());

//10个订单产生11次数据库查询

}

--✅优化:批量查询

Listorders=orderRepository.findByUserId(userId);

SetuserIds=orders.stream()

.map(Order::getUserId)

.collect(Collectors.toSet());

MapuserMap=userRepository.findAllById(userIds).stream()

.collect(Collectors.toMap(User::getId,u->u));

//2次数据库查询

--❌性能问题:深分页

SELECT*FROMorder_infoORDERBYidLIMIT1000000,20;

--需要扫描100万行

--✅优化:基于ID的游标分页

SELECT*FROMorder_info

WHEREid>1000000

ORDERBYidLIMIT20;

--❌性能问题:函数操作索引列

SELECT*FROMorder_infoWHEREDATE(created_at)='2026-09-19';

--索引失效

--✅优化:范围查询

SELECT*FROMorder_info

WHEREcreated_at>='2026-09-1900:00:00'

ANDcreated_at<'2026-09-2000:00:00';

--❌性能问题:大事务

@Transactional

publicvoidprocessOrders(ListorderIds){

for(Longid:orderIds){

//循环中执行多个操作,事务范围过大

orderRepository.updateStatus(id,OrderStatus.PROCESSED);

logRepository.save(newLog(id));

//可能锁住大量行

}

}

--✅优化:分批处理

publicvoidprocessOrders(ListorderIds){

for(Listbatch:Lists.partition(orderIds,100)){

processBatch(batch);

}

}

@Transactional

publicvoidprocessBatch(ListorderIds){

//每次只处理100条

orderRepository.updateStatusBatch(orderIds,OrderStatus.PROCESSED);

logRepository.saveBatch(orderIds);

}

4.2算法与数据结构审查

//❌性能问题:嵌套循环O(n²)

publicListfindCommonUsers(Listlist1,Listlist2){

Listresult=newArrayList<>();

for(Useru1:list1){

for(Useru2:list2){

if(u1.getId().equals(u2.getId())){

result.add(u1);

}

}

}

returnresult;

}

//1000x1000=100万次比较

//✅优化:使用HashSetO(n)

publicListfindCommonUsers(Listlist1,Listlist2){

Setids2=list2.stream()

.map(User::getId)

.collect(Collectors.toSet());

returnlist1.stream()

.filter(u->ids2.contains(u.getId()))

.collect(Collectors.toList());

}

//2000次操作

//❌性能问题:字符串拼接

Stringresult="";

for(Stringitem:items){

result+=item+",";

}

//每次循环创建新的字符串对象

//✅优化:使用StringBuilder

StringBuildersb=newStringBuilder();

for(Stringitem:items){

sb.append(item).append(",");

}

Stringresult=sb.toString();

//❌性能问题:ArrayList中间插入

Listlist=newArrayList<>();

for(inti=0;i<10000;i++){

list.add(0,"item"+i);//O(n)的插入

}

//总复杂度O(n²)

//✅优化:使用LinkedList或改变策略

Dequedeque=newArrayDeque<>();

for(inti=0;i<10000;i++){

deque.addFirst("item"+i);//O(1)

}

//❌性能问题:频繁扩容

Listlist=newArrayList<>();

for(inti=0;i<1000000;i++){

list.add("item"+i);//多次扩容

}

//✅优化:预设容量

Listlist=newArrayList<>(1000000);

for(inti=0;i<1000000;i++){

list.add("item"+i);//只扩容一次

//❌性能问题:HashMap遍历多次

Mapmap=getLargeMap();

for(Stringkey:keys){

if(map.containsKey(key)){//第一次查找

Integervalue=map.get(key);//第二次查找

}

}

//✅优化:一次查找

for(Stringkey:keys){

Integervalue=map.get(key);

if(value!=null){

//处理

}

}

4.3资源管理审查

//❌资源泄漏:未关闭连接

publicStringquery(Stringsql)throwsSQLException{

Connectionconn=dataSource.getConnection();

Statementstmt=conn.createStatement();

ResultSetrs=stmt.executeQuery(sql);

//忘记关闭,连接泄漏

returnrs.getString(1);

}

//✅使用try-with-resources

publicStringquery(Stringsql)throwsSQLException{

try(Connectionconn=dataSource.getConnection();

Statementstmt=conn.createStatement();

ResultSetrs=stmt.executeQuery(sql)){

returnrs.getString(1);

}

}

//❌资源浪费:线程池未复用

publicvoidprocessAsync(){

for(Tasktask:tasks){

newThread(()->process(task)).start();//每次创建新线程

}

}

//✅使用线程池

privatefinalExecutorServiceexecutor=

newThreadPoolExecutor(

4,16,60L,TimeUnit.SECONDS,

newLinkedBlockingQueue<>(1000),

newThreadPoolExecutor.CallerRunsPolicy()

);

publicvoidprocessAsync(){

for(Tasktask:tasks){

executor.submit(()->process(task));

}

}

//❌连接池配置不当

hikari:

maximum-pool-size:100#过大,可能压垮数据库

minimum-idle:50

//✅合理配置

hikari:

maximum-pool-size:20#根据数据库承载能力

minimum-idle:5

connection-timeout:30000

idle-timeout:600000

max-lifetime:1800000

//❌大对象未及时释放

publicvoidprocessLargeFile(){

byte[]data=readLargeFile();

//后续长时间不释放data

}

//✅及时释放

publicvoidprocessLargeFile(){

try(InputStreamis=newFileInputStream(file)){

//流式处理,避免一次性加载

}

}

4.4缓存使用审查

检查项说明影响

是否合理使用缓存?热点数据应该缓存大

缓存是否有过期时间?避免永久缓存中

是否防止缓存穿透?布隆过滤器或空值缓存中

是否防止缓存击穿?互斥锁或永不过期中

是否防止缓存雪崩?过期时间随机化中

缓存更新是否及时?写入时删除缓存高

缓存大小是否合理?避免内存溢出高

//❌缓存穿透:查询不存在的数据

publicUsergetUser(LonguserId){

Usercached=cache.get("user:"+userId);

if(cached!=null)returncached;

Useruser=userRepository.findById(userId).orElse(null);

if(user!=null){

cache.set("user:"+userId,user,300);

}

returnuser;

}

//恶意请求user_id=-1每次都打到数据库

//✅空值缓存

publicUsergetUser(LonguserId){

Stringkey="user:"+userId;

Objectcached=cache.get(key);

if(cached!=null){

returncached==NULL_MARKER?null:(User)cached;

}

Useruser=userRepository.findById(userId).orElse(null);

if(user!=null){

cache.set(key,user,300);

}else{

cache.set(key,NULL_MARKER,60);//空值短期缓存

}

returnuser;

}

//❌缓存雪崩:大量key同时过期

for(Useruser:users){

cache.set("user:"+user.getId(),user,3600);

}

//✅过期时间随机化

for(Useruser:users){

intttl=3600+ThreadLocalRandom.current().nextInt(600);

cache.set("user:"+user.getId(),user,ttl);

}

//❌缓存击穿:热点key过期瞬间大量请求

publicProductgetProduct(LongproductId){

Productcached=cache.get("product:"+productId);

if(cached!=null)returncached;

//1000个并发请求同时查到数据库

Productproduct=productRepository.findById(productId).orElse(null);

cache.set("product:"+productId,product,300);

returnproduct;

}

//✅互斥锁保护

publicProductgetProduct(LongproductId){

Stringkey="product:"+productId;

Productcached=cache.get(key);

if(cached!=null)returncached;

StringlockKey="lock:"+key;

try{

if(lock.tryLock(lockKey,3,TimeUnit.SECONDS)){

try{

//双重检查

cached=cache.get(key);

if(cached!=null)returncached;

Productproduct=productRepository.findById(productId)

.orElse(null);

cache.set(key,product,300);

returnproduct;

}finally{

lock.unlock(lockKey);

}

}else{

//未获取锁,短暂等待后重试

Thread.sleep(100);

returngetProduct(productId);

}

}catch(Exceptione){

log.error("获取商品失败",e);

thrownewRuntimeException(e);

}

}

4.5并发性能审查

//❌性能问题:同步锁粒度过大

publicclassCounter{

privateintcount

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论