ChatGPT 出来之后,我的写代码方式变了一、第一次用 AI 辅助写代码2023 年初,我在做一个数据导出功能,需要把一个嵌套的 JSON 结构展平成 Excel 表格,字段对应关系大概有二十几列,逻辑不复杂但很啰嗦。 以前这种活,我会先找类似的代码复制一份改一改,或者去 Stack Overflow 搜一下有没有现成的写法。那次我想着试一试,把需求描述给 ChatGPT,大意是「把这个 JSON 结构转换成以下表头的 Excel,用 EasyExcel」,附上了 JSON 样例和字段映射表。 它给出的代码大概对了 80%,剩下 20% 是字段名对不上和日期格式不对。但即便如此,我节省了大概一个小时的手写时间。从那之后,这类有明确规律但需要大量重复劳动的任务,我都会先问 AI。 二、现在哪几类任务会优先用 AI用了快一年之后,沉淀下来有几类任务是真实在用的: 写 SQL:特别是复杂的聚合查询(多表 JOIN + GROUP BY + HAVING)。我描述清楚需求和表结构,AI 给草稿,我来验证逻辑和加索引考虑。AI 给的 SQL 草稿大约有 70% 可以直接用,30% 需要调整。时 ...
ShardingJDBC 分库分表接入记录在评估过 MyCat2 之后,因为 SQL 兼容性问题(跨分片 JOIN、复杂子查询)最终选了 ShardingJDBC。详细选型对比可以看上一篇:MyCat2 使用记录与放弃复盘。 ShardingJDBC(现在叫 ShardingSphere JDBC 模式)以 JAR 包集成进应用,在 JDBC 层拦截 SQL,对 SQL 做解析、改写和路由。相比代理模式少一跳网络,性能更好,SQL 兼容性也更强。 一、环境与版本 ShardingSphere 版本:5.4.1 Spring Boot 版本:2.7.x 数据库:MySQL 8.0,2 个实例,每实例各 2 个 schema(order_db_0 / order_db_1) 分片表:t_order,目标是 2 库 × 4 表 = 8 个物理分片 二、接入步骤引入依赖<dependency> <groupId>org.apache.shardingsphere</groupId> <artifactId>s ...
kubectl 之外:让 K8s 日常运维不那么痛的工具刚上 K8s 时,每次排查问题都要敲一大串命令:kubectl get pods -n production、kubectl logs -f order-service-67d8f9c5b-xkp2t -n production……Pod 名每次都在变,Namespace 还要手动指定,效率极低。这四个工具,解决的正是这个摩擦。 k9s:终端里的 K8s 可视化# 安装(macOS)brew install derailed/k9s/k9s# Linux 直接下载二进制curl -sS https://webinstall.dev/k9s | bash# 启动k9s k9s 是一个终端 UI,启动后实时显示所有 Pod 的状态、重启次数、CPU/内存用量。 常用快捷键: :namespace 或 :ns — 切换 Namespace l — 查看当前选中 Pod 的日志(实时滚动) s — 进入容器 Shell(等同于 kubectl exec -it) d — describe 当前资源(等同于 kubectl ...
从 Docker Compose 迁到 K8s:踩坑实录迁移策略:哪些服务先动迁移不是一次性的,我们采用的策略是无状态服务优先、按流量从小到大。 第一批先迁 user-service 和 product-service——无状态,没有持久化需求,出了问题回滚也容易。第二批迁 order-service 和 promo-service,有数据库依赖,需要把 PVC 配好。中间件(MySQL、Redis、RabbitMQ)保持 Docker Compose 运行,不在这次迁移范围里。 整个迁移前后花了大概 6 周,期间线上始终保持可用。 坑一:Pod 一直 CrashLoopBackOff现象 order-service 部署上去,Pod 状态一直是 CrashLoopBackOff,kubectl logs 看到的错误是: Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.java.lang. ...
MyCat2 使用记录与放弃复盘做分库分表选型,最先评估的就是 MyCat2。吸引我的地方很直接:代理模式,应用像连普通 MySQL 一样连 MyCat,业务代码不需要改动。团队当时对 ShardingJDBC 的配置复杂度有顾虑,所以 MyCat2 排在第一位评估。 结论先说:搭建验证通过了,但跑现有业务 SQL 发现了几个无法绕过的限制,最终放弃,改用 ShardingJDBC。 一、为什么先评估 MyCat2分库分表主流方案的核心差异只有一个维度:代理模式 vs JDBC 层拦截。 MyCat2(代理模式):应用连 MyCat,MyCat 连后端数据库,应用看到的是「一个普通 MySQL」,业务代码零改动 ShardingJDBC(JDBC 层):以 JAR 包集成进应用,在 JDBC 层拦截 SQL 做路由改写,需要引入依赖和配置 选 MyCat2 的理由:不改业务代码,迁移成本低;支持多语言项目(PHP 老服务也能用)。 选 ShardingJDBC 的理由:进程内处理,无额外网络跳转,性能更好;SQL 兼容性更强;Java 生态支持最完善。 二、搭建过程环境 MyC ...
给团队做了一次技术分享,暴露了我自己一、分享的主题和背景2023 年春天,我们团队决定把 DDD 作为一个季度的技术学习方向。组长说:你之前在系统重构里用过,要不你来讲一次? 我答应了。当时觉得没什么问题——DDD 的那次重构项目我做了将近半年,领域边界、聚合根、值对象、领域事件,这些我都实践过,讲个两小时应该没难度。 二、备课时遇到的知识漏洞备课的第一天,我开始把要讲的内容列大纲。 讲到”聚合根”这一块,我想写一段对聚合根的解释——什么是聚合根、为什么要有聚合根、什么情况下需要一个,什么情况下不需要。 写到”为什么”的时候,我卡住了。 我能描述聚合根”是什么”:它是聚合的入口,外部不能直接访问聚合内部的实体,只能通过聚合根。这句话我能背出来。但如果有人问我:为什么不直接操作内部实体?聚合根的约束到底保护了什么? 我发现我说不清楚。 我用了两年 DDD,那次重构就是按这个模式来的,代码也跑着。但当我试图把”为什么”这件事解释清楚,我发现我的理解里有一个漏洞——我知道怎么做,但没有真正理解背后的设计意图。 那天晚上重新读了 Evans 原书里关于聚合的章节,才把这个问题想清楚:聚合根的存 ...
MyBatis-Plus 多数据源动态切换接入记录项目里有三个库:核心业务库(主从各一个)+ 日志库(单独存操作日志)。早期的做法是手动配了三个 DataSource Bean,加上三套 SqlSessionFactory,光配置类就写了两三百行,还经常忘了在哪个 Mapper 上指定 sqlSessionTemplate。 接入 dynamic-datasource-spring-boot-starter 之后,配置文件加几行,业务层加个 @DS 注解,问题解决。 一、使用场景什么情况下需要多数据源: 读写分离:主库负责写,从库负责读,减轻主库压力 业务隔离:核心业务库 + 日志库 + 报表库,不同业务操作不同数据库 数据集成:需要从外部系统的数据库读取数据(如 ERP、财务系统) 为什么不手动配多个 DataSource Bean: 手动配置需要维护多套 SqlSessionFactory + TransactionManager,代码量大 切换数据源时要在 ThreadLocal 里手动设置,业务代码和数据源逻辑耦合 dynamic-datasource 通过 @DS 注 ...
微服务架构里,”分布式事务”是个绕不开的问题。在做订单相关业务时,一次下单操作需要同时写订单服务、库存服务、积分服务,如果中间某个服务挂了,就会出现数据不一致的情况。 引入 Seata 是为了解决这个问题。Seata 是阿里开源的分布式事务框架,支持 AT、TCC、SAGA、XA 四种模式。项目里用的是 AT 模式,改造成本最低,只需要加一个注解。 AT 模式原理简述AT 模式基于对业务代码无侵入的两阶段提交: 一阶段:每个参与者(RM)在本地数据库执行 SQL,同时在同一个库里的 undo_log 表记录”回滚日志”(前镜像 + 后镜像),然后向 Seata TC(事务协调者)注册分支事务。 二阶段提交:如果所有分支都成功,TC 通知各 RM 删除 undo_log,提交完成。 二阶段回滚:如果有分支失败,TC 通知各 RM 根据 undo_log 恢复数据,再删除日志。 优点:业务代码基本不需要改,只加 @GlobalTransactional。缺点:性能有损耗(写 undo_log + 全局锁),适合对强一致性有要求但不是极高并发的场景。 部署 Seata Server( ...
技术学习
未读微服务到底给我们带来了什么一、当初为什么要做微服务那是 2019 年底,单体项目已经跑了三年,代码量大概是 40 万行,十几个人的团队在同一个 Git 仓库里写代码。 问题不是一开始就很严重的。慢慢地,我们开始注意到一些小事:一个前端改了首页的推荐逻辑,要等后端同学把订单、库存、商品三个模块都合并完才能发版;某个节日活动的促销模块流量突然翻了 5 倍,但整个项目只能整体扩容,把用不上的模块也跟着扩了一遍,成本浪费明显。 最终推动拆分的直接原因,是有一次上线,测试同学发现了一个回归 Bug,追查下来是 A 同学的改动影响了 B 同学改的逻辑,两个人的代码耦合在了同一个 Service 里。那次修复耽误了三天,所有人的需求都压在那里等着。 技术负责人开始认真讨论微服务方案,核心诉求是两个:独立部署和模块隔离。 二、拆分完之后,解决了什么有几件事确实变好了: 1. 促销模块可以单独扩容了 活动期间只需要把 promo-service 的实例数拉起来,其他服务不动。这个效果是立竿见影的,大促期间的成本比之前整体扩容节省了大概 30%。 2. 团队发版解耦 商品团队和订单团队不再互相等待,各自维 ...
我们为什么决定把项目迁到 K8s一、迁移前的现状2022 年底,我们的部署方式是 Docker Compose,一套文件管着大概 12 个服务。 在早期,这套方式挺好用的——本地起环境方便,测试环境和生产环境的配置差异一目了然,出了问题 docker logs 一看就能定位。但随着服务数量增多,问题开始出现: 每次发布都需要登上服务器,手动 docker-compose pull 再 docker-compose up -d,几个服务要挨个操作,容易漏。一个服务挂了没有自愈机制,要人肉发现、手动重启。 最直接的痛:有一次一个内存泄漏的问题,订单服务每隔几个小时 OOM 重启一次,凌晨两点告警打过来,我爬起来上服务器 restart。这不是偶发的,差不多持续了一个月,直到问题修完。 能自动重启、能自动扩容、发布时不停服——这些需求越来越迫切。 二、触发决策的那件事真正让我下定决心要迁的,是一次大促前的部署演练。 我们做了一次压测,模拟高峰流量,发现有两个服务在大流量下响应变慢,需要加实例。手动扩容的流程是:登服务器 → 改 docker-compose.yml 的 replicas → ...

