暑假实习总结

暑假 Java 后端实习总结:两个月里我做了什么,又学到了什么

本文记录我的一次 Java 后端实习经历。出于一些考虑,文中的产品名称、业务数据、表名和代码都做了一些简化。

前言

暑假,我在一家武汉小规模的互联网公司实习了两个月,岗位是 Java 后端开发实习生。

这次实习所在的团队并不大,技术部前后端+测试一共9个人,项目也不是什么"日活千万、每秒几万请求"的大型系统,就是一个有真实用户、已经运行了一段时间的社区产品,每日活跃用户大概1w。

不过,对当时的我来说,它依然比学校里做过的项目复杂很多。

学校项目一般是自己从头开始搭,数据库表、接口和代码结构都比较清楚。公司项目完全不一样,代码量比较大,有不少历史逻辑,同一个字段可能在用户端、运营后台和定时任务里都被修改。

有时候需求看上去只需要改几行代码,真正开始做之后,才发现它还会影响缓存、统计、通知、审核记录和旧数据。

实习期间,我参与了帖子、评论、角色、头像、内容审核和群聊机器人等模块的开发,也处理了一些测试环境和线上环境的问题。

这篇文章不会按照工作日报逐条罗列,而是挑几个我印象比较深的需求和问题,聊一聊自己当时是怎么做的,以及后来有哪些新的理解。


一、项目大概是什么样的

我参与的是一个二次元为主的兴趣社区项目。

用户可以使用不同的虚拟角色发帖、评论、加入群聊,也可以申请新的角色和上传角色头像。运营人员则通过管理后台审核帖子、评论、角色和头像,同时管理群聊机器人。

项目主要使用:

  • Java 8
  • Spring Boot
  • MongoDB
  • MySQL
  • Redis
  • Redisson
  • MyBatis-Plus
  • CompletableFuture
  • JUnit 5

项目整体上是一个 Maven 多模块单体。

帖子、评论、角色、头像和群组等数据主要放在 MongoDB 中。

系统配置、机器人配置和部分统计记录放在 MySQL 中。

Redis 主要用于缓存、登录状态、频率限制和分布式锁。

这些技术我之前在学校项目里多多少少接触过一些,但那时候基本只是"会用"。真正进入一个已经运行的项目后,我才慢慢理解为什么要这样用,以及使用之后还会带来哪些问题。


二、刚接手项目时,我有点不知道从哪里开始

实习第一周比较直接的感受就是:代码太多了,我主要看的部分有admin的前后端代码,以及app的后端代码。

在自己学习做的项目里,一个请求通常就是:

text 复制代码
Controller
    ↓
Service
    ↓
Mapper
    ↓
MySQL

但公司项目中,一个帖子接口可能同时涉及:

  • 帖子本身;
  • 发布角色;
  • 星球信息;
  • 话题;
  • 评论数;
  • 点赞状态;
  • 好友关系;
  • 审核状态;
  • 缓存;
  • 消息通知;
  • 成就系统。

一开始我接到需求后,会直接搜索接口名称,然后从 Controller 往下看。

后来发现,只看接口调用链还不够。因为有些状态不只在这个接口里修改,运营后台、定时任务和异步线程也可能修改同一条数据。

后面我逐渐形成了一个比较固定的习惯:

  1. 先找到接口入口;
  2. 看主要 Service;
  3. 找到对应实体和数据库字段;
  4. 全局搜索关键字段的所有读写位置;
  5. 查看相关代码的历史提交;
  6. 列出这个需求可能影响的其他模块;
  7. 最后再开始修改。

这个过程看起来有点慢,但是借用ai去做效率也是不低的,而且很大程度上降低了ai乱改动代码的风险,比改完之后不断补 Bug 要好一些。


三、第一次真正注意到"异步结果可能已经过期"

实习期间,我参与比较多的是 AI 内容审核。

帖子、评论、角色和头像提交后,系统会调用外部 AI 服务进行审核。因为 AI 接口响应比较慢,所以部分审核任务是异步执行的。

流程大概是:

text 复制代码
用户提交内容
    ↓
后端先保存数据
    ↓
状态设置为"审核中"
    ↓
把 AI 审核任务放进线程池
    ↓
接口先返回给用户
    ↓
AI 返回结果后再更新数据库

一开始我觉得这个流程比较简单,无非就是调用接口、解析 JSON,然后把结果写回数据库。

后来测试时出现了一个问题:运营人员已经在后台完成人工审核,但过了一会儿,状态又被 AI 修改了。

3.1 问题是怎么产生的

可能的执行顺序是:

text 复制代码
用户提交申请
    ↓
AI 开始审核
    ↓
运营人员先人工审核通过
    ↓
AI 结果稍后返回
    ↓
AI 把状态重新修改

原来的逻辑大概相当于:

java 复制代码
AuditRecord record = findById(recordId);

record.setAiAuditResult(aiResult);
record.setStatus(targetStatus);

update(record);

只要这条数据还存在,AI 就会继续更新,并不知道人工已经处理过了。

我最开始想到的办法也是先查一下状态:

java 复制代码
if (record.getStatus() == AUDITING) {
    updateAiResult(record);
}

但后来继续分析发现,这样其实还是不安全。

因为"查询"和"更新"是两步操作。

可能在线程查询到"审核中"之后,人工审核刚好完成,接着 AI 线程仍然会继续更新。


3.2 把判断条件放进数据库更新里

最后采用的思路是:不要先查询再判断,而是在更新数据库时直接带上条件。

简化后的写法类似:

java 复制代码
Query query = new Query();

query.addCriteria(
    Criteria.where("_id").is(recordId)
        .and("status").is(AUDITING)
        .and("audit_time").is(null)
);

Update update = new Update()
    .set("ai_audit_status", aiResult)
    .set("ai_audit_reason", aiReason)
    .set("status", targetStatus);

long updatedCount = updateFirst(query, update);

只有状态仍然是"审核中",并且人工审核时间还是空时,AI 才允许更新。

如果更新数量是 0,就说明数据已经被其他流程处理了,这个 AI 结果已经过期,直接忽略即可。

这也是我第一次在真实业务里比较直观地理解"条件更新"的作用。

以前学习数据库时,知道单条文档更新是原子的,但没有真正想过它可以用来解决这种并发状态问题。


3.3 用户重新提交也会产生旧结果覆盖

处理完人工审核覆盖后,又发现了另一个类似的问题。

如果用户修改角色资料并重新提交,就可能同时存在两次 AI 请求:

text 复制代码
第一次提交
    ↓
AI 请求 A 开始

用户修改后再次提交
    ↓
AI 请求 B 开始

请求 A 比请求 B 更晚返回
    ↓
第一次结果覆盖第二次提交

仅仅判断当前状态是不是"审核中"已经不够了,因为第二次提交后,状态同样是审核中。

所以每次提交时,还会生成一个新的审核请求 ID:

java 复制代码
String requestId = generateRequestId();

并保存到当前申请中:

java 复制代码
Update update = new Update()
    .set("ai_audit_request_id", requestId)
    .unset("ai_audit_status")
    .unset("ai_audit_reason");

AI 回写时,除了匹配业务 ID 和审核状态,还要匹配请求 ID:

java 复制代码
Criteria.where("_id").is(recordId)
    .and("status").is(AUDITING)
    .and("ai_audit_request_id").is(requestId);

如果用户已经重新提交,数据库中的请求 ID 就会发生变化,旧 AI 请求自然无法更新新版本的数据。

我后来把它理解成一个比较简单的业务版本号。


3.4 AI 服务异常时怎么办

外部 AI 服务并不总是稳定,实际开发中遇到过不少需要兼容的情况:

  • 请求超时;
  • 返回状态码异常;
  • 返回体为空;
  • 缺少约定字段;
  • 返回内容不是合法 JSON;
  • JSON 外面带着 Markdown 代码块;
  • 原本约定返回英文,实际返回了中文;
  • 返回了系统没有定义的状态。

刚开始写这类代码时,我容易把注意力放在正常响应上。但真正联调后会发现,异常响应的处理量可能并不少。

审核系统有一个比较重要的原则:

AI 调用失败时不能直接当作审核通过。

否则一旦第三方服务异常,所有内容都有可能绕过审核。

项目中不同内容的处理方式不完全一样,有的会继续等待人工审核,有的会进入限制可见状态。但总体思路都是:记录异常原因,保留业务 ID,不默认公开。


3.5 为什么还需要审核历史

角色申请可以被用户多次修改。

如果每次都只覆盖当前记录,那么最后只能看到最新内容,不知道前几次提交了什么,也不知道为什么被拒绝。

因此,审核完成后还需要保存一份快照,包括:

  • 申请 ID;
  • 第几次提交;
  • 审核结果;
  • 审核人;
  • 拒绝原因;
  • 审核时间;
  • 当时的角色名称、简介和头像等信息。

保存时可以使用"申请 ID + 提交次数"作为业务唯一条件。

同一个提交版本重复保存时更新原记录,不会不断产生重复历史。

当然,这种方案保留的是每个提交版本的最终结果。如果以后要求保留运营人员的每一次点击操作,还需要单独设计操作流水。


3.6 这部分给我的最大收获

以前提到异步,我想到的主要是"提高响应速度"。

做完这部分后,我才发现异步最麻烦的不是怎么创建线程,而是:

任务执行完成时,原来的业务条件是否还成立?

后面再看到异步代码时,我会主动多想几个问题:

  • 结果可能乱序吗?
  • 同一个任务可能执行多次吗?
  • 用户可能已经提交新版本吗?
  • 人工可能已经修改状态吗?
  • 失败之后需要重试吗?
  • 旧结果回来后如何识别?

这些都是学校项目里比较少遇到的。


四、原以为只是"计个数"的发帖频率限制

另一个让我印象比较深的需求是发帖频率限制。

需求本身不难理解:用户不能在短时间内连续发太多帖子,每天也要有一个发布上限。

但开始设计后,需要确定的问题还挺多:

  • 按账号、角色还是 IP 限制?
  • 普通帖和投票帖是否一起计算?
  • 编辑帖子算不算发帖?
  • 参数校验失败算不算一次?
  • 发布失败后要不要计数?
  • 多个服务实例同时收到请求怎么办?
  • 修改配置后什么时候生效?
  • Redis 异常后是放行还是拒绝?

这些问题如果没有提前确认,最后很容易出现后端认为正确、产品认为不对的情况。


4.1 为什么按照账号限流

这个产品允许同一个账号使用多个角色。

如果按照角色 ID 限制,用户切换角色后就可以继续发帖,相当于绕过限制。

如果只按照 IP,又可能误伤同一个网络环境下的多个用户。

所以最终使用登录账号的 userId 作为主要限流维度。


4.2 短时间窗口为什么使用 ZSet

短时间限制使用 Redis ZSet。

score 保存发帖时间戳,member 使用"时间戳 + 随机值"。

每次检查时:

  1. 删除时间窗口外的记录;
  2. 查询当前窗口内还有多少条;
  3. 判断是否达到限制;
  4. 发布成功后再记录本次时间。

简化后的代码类似:

java 复制代码
long now = System.currentTimeMillis();

redis.opsForZSet().removeRangeByScore(
    key,
    0,
    now - windowMillis
);

Long count = redis.opsForZSet().zCard(key);

if (count != null && count >= limit) {
    throw new RuntimeException("发帖频率过快");
}

发布成功后再添加记录:

java 复制代码
String member = now + ":" + UUID.randomUUID();

redis.opsForZSet().add(key, member, now);
redis.expire(key, Duration.ofSeconds(windowSeconds));

member 后面拼随机值,是为了避免同一毫秒出现多个请求时互相覆盖。


4.3 为什么还需要分布式锁

虽然 Redis 的单个命令是原子的,但完整流程不是一个命令:

text 复制代码
检查冷却状态
    ↓
删除过期记录
    ↓
查询当前数量
    ↓
发布帖子
    ↓
记录次数

如果两个请求同时执行,可能都查询到还没有超过限制,然后一起发布成功。

因此项目中按照 userId 使用 Redisson 分布式锁。同一个账号的并发发帖请求需要依次处理,不同账号之间不受影响。

java 复制代码
RLock lock = redissonClient.getLock(
    "POST:FREQUENCY:LOCK:" + userId
);

boolean locked = lock.tryLock(
    waitSeconds,
    TimeUnit.SECONDS
);

锁需要在 finally 中释放,并且释放前要判断是不是当前线程持有。


4.4 为什么发布成功后才增加次数

如果一进入接口就增加次数,可能发生:

text 复制代码
用户提交请求
    ↓
计数加一
    ↓
参数校验失败
    ↓
帖子没有发布

这样用户没有成功发帖,却消耗了一次额度。

所以限流流程是:

java 复制代码
checkLimit();

Post post = publish();

recordSuccessfulPublish();

return post;

只有真正发布成功后才计数。

不过,这个方案也不是完全没有问题。

如果帖子已经写入 MongoDB,但应用在写 Redis 前发生异常,就可能少计算一次。

对于普通社区发帖,这种小概率误差可以暂时接受。如果是支付或者强风控业务,就需要使用更加严格的事务事件或额度预占方案。

这也是我在实习中慢慢学到的一点:很多技术方案不是"绝对正确",而是看当前业务能接受什么程度的误差。


4.5 Redis 异常时该不该放行

这个问题当时也让我思考了很久。

如果 Redis 异常时所有请求都拒绝,那么限流组件本身会影响正常发帖。

如果 Redis 异常时直接放行,又可能在故障期间失去限流保护。

当前业务不是支付和资金相关业务,限流主要是防止灌帖,所以更倾向于记录异常后降级放行,优先保证主流程可用。

如果换成登录防爆破、支付或高风险操作,策略可能完全不同。


4.6 动态配置和本地缓存

限流参数保存在 MySQL 系统配置表中。

如果每次发帖都查询一次数据库,会产生没有必要的压力,所以代码中增加了几秒钟的本地缓存。

java 复制代码
private volatile LimitConfig cachedConfig;
private volatile long configExpireAt;

缓存过期后,再使用同步块刷新。

这里用到的技术并不复杂,但是真正在项目里遇到后,我才对 volatile 的可见性和双重检查有了更具体的理解。

以前背概念时比较抽象,现在能够对应到"多个请求线程同时读取动态配置"这个实际场景。


4.7 这个方案还可以怎么改

现在回头看,当前方案还有一些不足:

  • 一次检查包含多次 Redis 操作;
  • 分布式锁会覆盖整个发帖过程;
  • 短窗口和每日计数不是同一个原子操作;
  • Redis 计数失败后没有补偿;
  • 缺少限流命中次数和降级次数监控。

如果继续优化,可以用 Lua 脚本合并部分 Redis 操作,减少网络交互。

但因为帖子必须发布成功后才能确认计数,所以即使用 Lua,也仍然需要考虑数据库写入和 Redis 计数之间的一致性。


五、一个"小需求"牵出来的评论数问题

还有一个需求表面上非常简单:某些无意义评论需要隐藏,但发布者自己仍然能够看到。

一开始我以为只要给评论加一个"隐藏"状态,然后查询时过滤就可以了。

真正改起来才发现,它会影响很多地方:

  • 评论列表;
  • 评论内容展示;
  • 帖子评论数;
  • 回复数量;
  • 帖子热度;
  • 删除逻辑;
  • 成就进度;
  • 后台审核。

5.1 "本人可见"到底指谁

这个社区允许同一个账号使用多个角色。

因此,"隐藏评论只有本人可见"最后确认的含义是:

只有发布这条评论的具体角色可以看到。

同一个账号切换成另一个角色后,也不能看到这条隐藏评论。

查询条件大概是:

java 复制代码
Criteria visibility = new Criteria().orOperator(
    Criteria.where("status").is(ONLINE),
    Criteria.where("status").is(HIDDEN)
        .and("author_role_id").is(currentRoleId)
);

5.2 为什么评论数会对不上

假设一个帖子有:

text 复制代码
10 条公开评论
1 条角色 A 发布的隐藏评论

那么:

text 复制代码
角色 A 应该看到 11 条
角色 B 应该看到 10 条
未登录用户应该看到 10 条

如果隐藏评论创建后,直接把帖子中的公共 replyCount 加一,其他用户就会看到评论数是 11,但点进去只有 10 条。

所以隐藏评论不能进入所有用户共享的公开评论数。

返回帖子数据时,再根据当前角色补充其自己的隐藏评论数。


5.3 避免逐个帖子查询

帖子列表一次可能返回很多条数据。

如果每个帖子都单独查询一次当前角色的隐藏评论,就会产生 N+1 查询。

最后采用 MongoDB 聚合,一次传入这一页所有帖子 ID,按帖子 ID 分组统计当前角色可见的评论数,再将结果填充回帖子列表。

这个需求让我比较直观地感受到,接口中的一个数字也需要和实际数据展示保持同一口径。


5.4 删除逻辑也不能直接复用

隐藏评论创建时没有增加公开评论数,也没有增加一些公开评论相关的成就进度。

因此删除隐藏评论时,也不能照搬普通评论删除逻辑。

否则可能把帖子评论数错误减一,或者把用户的成就进度错误回退。

我以前写业务代码时,容易把"删除"理解成修改删除状态。后来发现,删除前必须先知道这条数据创建时产生过哪些副作用,删除时才能决定需要撤销哪些内容。


六、机器人管理中的跨数据库问题

运营后台需要配置群聊机器人,一个机器人还可以加入多个群。

机器人配置放在 MySQL 中,群成员关系放在 MongoDB 中。

MySQL 中采用"一机器人一群一行"的方式保存,后台查询时再按照用户 ID 和角色 ID 聚合成一个机器人。


6.1 已经在群里的用户为什么不能成为机器人

有一次遇到的问题是:某个角色本来已经在群里,运营再把它设置成机器人时,保存失败。

排查后发现,新增机器人时会固定调用一次加群逻辑。

角色已经是群成员,再次加群就会触发"重复入群"的校验,导致后面的机器人配置没有保存。

原来的流程相当于:

text 复制代码
新增机器人
    ↓
执行加群
    ↓
保存机器人配置

修改后变成:

text 复制代码
查询是否已经是群成员
    ↓
不是群成员:先加群
已经是群成员:跳过加群
    ↓
保存机器人配置

这个问题的根本原因是:

text 复制代码
"已经在群里"
和
"已经被配置成机器人"

实际上是两个不同的状态,不能认为已经在群里就不需要继续后面的操作。


6.2 先查询再插入也不是绝对安全

虽然增加前置查询可以解决大部分重复操作,但两个请求同时执行时,仍然可能都查询到不存在,然后一起插入。

所以关键业务还需要数据库唯一索引兜底,例如:

text 复制代码
user_id + role_id + group_id

以前我经常认为"代码里判断过了就不会重复",实习后才慢慢意识到,应用层判断和数据库约束解决的是不同层次的问题。


6.3 @Transactional 解决不了所有事务问题

机器人配置在 MySQL,群成员在 MongoDB。

即使方法上添加了 @Transactional,也不能自动让两个数据库一起提交、一起回滚。

可能出现:

text 复制代码
MongoDB 加群成功
    ↓
MySQL 保存机器人配置失败
    ↓
两个数据库状态不一致

实习期间的方案主要是通过前置检查、幂等和异常日志降低问题概率,并没有实现严格的跨库强一致。

如果以后要继续完善,可以增加:

  • 带状态的任务表;
  • 失败重试;
  • 补偿逻辑;
  • 定时对账;
  • Outbox;
  • 事务消息。

这部分我目前也只是有了基本认识,还没有真正独立设计过完整的分布式事务方案。


七、关于机器人数据看板

除了机器人配置,我还参与了机器人触发记录和数据看板。

看板需要统计:

  • 今日触发次数;
  • 昨日触发次数;
  • 活跃用户数;
  • 不同触发类型;
  • 按小时或按天的趋势;
  • 关键词分布;
  • 用户高频问题;
  • 新手群高频问题。

其中有几个细节以前很容易忽略。


7.1 时间范围使用左闭右开

时间查询使用:

sql 复制代码
created_at >= start_time
AND created_at < end_time

例如统计 8 月 1 日:

text 复制代码
[2026-08-01 00:00:00, 2026-08-02 00:00:00)

这样 8 月 2 日零点的数据只会进入第二天,不会被两天重复统计。


7.2 昨日数量为 0 时不能直接算增长率

增长率一般是:

text 复制代码
(今日数量 - 昨日数量) / 昨日数量

如果昨日为 0,就会除以 0。

项目中可以返回空值,让前端展示"暂无对比",而不是随便返回 0%。

这个问题很小,但如果没有处理,接口就可能在没有历史数据时直接异常。


7.3 实时统计并不适合所有数据量

当前数据规模下,可以直接从触发记录中按照时间和类型进行 GROUP BY

这样实现简单,结果也比较及时。

但数据量增大后,按时间分组、关键词分组和 COUNT(DISTINCT user_id) 都可能变慢。

如果以后数据量增加,可以改成按小时预聚合:

text 复制代码
原始记录
    ↓
小时统计任务
    ↓
小时统计表
    ↓
日报、周报从统计表查询

实习期间我没有真正接触特别大的数据量,所以这方面更多是根据当前实现做的思考,不能说自己有大数据系统经验。


八、测试和问题排查给我的帮助

实习期间,我使用 JUnit 5 和 Mockito 给部分核心逻辑补充了单元测试。

例如发帖限流会测试:

  • 限流关闭时是否直接放行;
  • 达到阈值后是否进入冷却;
  • 冷却期间是否阻止发布;
  • 发布失败后是否增加计数;
  • 跨北京时间零点时如何重置。

评论隐藏会测试:

  • 发布角色能否看到原文;
  • 其他角色是否看不到;
  • 隐藏评论是否影响公共评论数;
  • 删除隐藏评论时是否错误扣减计数。

AI 审核会测试:

  • 再次提交时是否清理旧结果;
  • 请求 ID 是否更新;
  • AI 状态映射是否正确;
  • 审核快照是否保存;
  • 同一提交版本是否产生重复历史。

我以前写测试比较容易只覆盖"正常返回成功"的情况。实习后发现,真正值得固定下来的往往是边界规则。


8.1 我常用的问题排查过程

遇到测试或线上问题后,我一般会先确认:

  • 用户 ID;
  • 业务对象 ID;
  • 发生时间;
  • 操作入口;
  • 预期结果和实际结果。

然后根据这些信息检索日志,再查询 MongoDB 或 MySQL 中的数据状态。

大致流程是:

text 复制代码
确认问题现象
    ↓
根据业务 ID 搜索日志
    ↓
找到请求和异步任务
    ↓
查询数据库当前状态
    ↓
根据时间还原状态变化顺序
    ↓
搜索所有可能修改该字段的代码
    ↓
构造复现场景
    ↓
修复并验证

我印象比较深的就是前面提到的 AI 覆盖人工审核问题。

单看日志时,每一步似乎都成功了;把 AI 请求时间、人工审核时间和数据库更新时间放在一起,才发现问题出在执行顺序上。


8.2 日志不能只写"操作失败"

以前我可能会写:

java 复制代码
log.error("AI审核失败");

这种日志真正出问题时帮助不大。

后来会尽量带上:

  • 业务类型;
  • 业务 ID;
  • 请求 ID;
  • 当前状态;
  • 目标状态;
  • 异常堆栈。

例如:

java 复制代码
log.error(
    "AI审核失败, bizType={}, bizId={}, requestId={}",
    bizType,
    bizId,
    requestId,
    exception
);

尤其是异步任务,如果没有业务 ID,很难和最初的用户请求对应起来。


九、这次实习中做得不够好的地方

回头看这两个月,肯定也有不少做得不够好的地方。

1. 有时过于关注当前需求

刚开始接需求时,我经常只关注产品明确写出来的主流程,没有主动想到旧数据、重复请求和异步结果。

后面出现问题之后,才逐渐养成全局搜索状态字段和检查其他写入口的习惯。

2. 对监控和性能了解得不够

我参与了日志排查和数据库查询,但没有完整负责过服务监控、容量评估和性能压测。

所以我可以分析某个 SQL 或聚合在数据量增大后可能出现的问题,但不能把自己包装成有高并发系统经验。

3. 跨库一致性只处理了具体问题

机器人配置中使用了 MongoDB 和 MySQL,我主要处理的是重复加群、状态检查和幂等问题,并没有实现完整的跨库事务方案。

这部分也是我后续想继续学习的内容。

4. 对历史代码的理解有时不够完整

项目中部分审核逻辑经过多次调整,新旧实现同时存在。刚开始修改时,如果只看当前方法,很容易忽略其他模块中的旧逻辑。

后来我会更多地查看 Git 历史和全局引用,但这方面仍然需要继续积累经验。


十、两个月实习后,我对后端开发的理解

实习前,我觉得后端开发主要是:

text 复制代码
设计数据库表
写接口
实现业务逻辑
返回数据

实习后,我觉得还要加上很多内容:

text 复制代码
并发时会不会出错
重复执行是否安全
异步结果是否过期
第三方失败后怎么处理
缓存和数据库是否一致
旧版本是否还能使用
统计口径是否统一
出了问题能不能快速找到原因

一个接口正常返回,并不代表一个需求已经真正完成。

例如:

  • AI 审核接口调用成功,不代表回写状态一定正确;
  • 隐藏评论保存成功,不代表评论数一定正确;
  • 机器人加群成功,不代表 MySQL 配置一定成功;
  • Redis 限流生效,不代表数据库和计数绝对一致;
  • 操作日志保存成功,也不代表日志语义一定准确。

这些问题听起来比较琐碎,却是我这次实习中接触最多的内容。


结语

这次实习所在的公司规模不大,项目也没有特别夸张的并发量,其实可以说几乎没有什么并发问题。

但对一个第一次正式参与真实项目的大三学生来说,这两个月还是让我学到了很多学校项目中接触不到的东西。特别是git相关以及不同环境部署,Linux服务器相关的,查询日志排查错误,以及使用宝塔配置定时任务等。

我现在仍然有很多不了解的地方,也还没有真正经历过大型系统的设计和优化。因为公司人员少,项目需求多,公司老师也很少指导我相关技术以及业务代码的规范,小公司更看中能不能解决这个需求,而对于实习生的培养并没有特别上心,但至少经过这次实习,我对后端开发以及职场有了更基本的认识,也知道了自己接下来应该朝什么方向去走。

相关推荐
liangsheng_g1 小时前
SpringAOP拦截器链递归与事务钩子补偿源码实战
java·spring
SL_staff2 小时前
制造业私有化文档平台的技术实践:从知识孤岛到可追溯知识资产
java·spring·开源
IT_陈寒3 小时前
Java Stream处理大集合,我的内存怎么就炸了
前端·人工智能·后端
悟空码字3 小时前
四轮对话两张配图:用 WorkBuddy 优化公众号发文配图的实战指南
人工智能·后端·腾讯
ServBay3 小时前
xAI的 Grok Bot发布,AI 已经学会自己上班了
后端·ai编程·grok
分支预测失败3 小时前
RISC-V 多核缓存一致性机制解析:MESI 协议族、CMO 扩展与 Linux 同步原语
后端
n8n3 小时前
Spring AI 检索增强生成(RAG)实战:让模型掌握你的私有知识
后端
Nturmoils4 小时前
只备份一个 schema,别把整库都搬走
后端
2501_933923254 小时前
统一功能:统一返回格式+统一异常处理
spring·java-ee·状态模式·统一数据返回