一个Python后端折腾MyBatis的碎碎念
我在上海一家医疗软件公司写Python,日常Flask加SQLAlchemy。上个月接了个医院老系统改造的活儿,对面技术栈是Java加MyBatis,架构师让我去理清持久层逻辑,方便做数据迁移。
翻了两天源码,发现MyBatis跟SQLAlchemy是两个路子:SQLAlchemy把SQL藏起来让你写Python对象,MyBatis反着来,把SQL赤裸裸摆在XML里。对于医疗系统这种查询复杂到变态的场景,手写SQL反而更可控。患者就诊记录表单表几百万行,联表查询五六个,ORM自动生成的SQL跑一次要八九秒,MyBatis里手工优化加索引能压到两百毫秒以内。
性能优化有几个坑。MyBatis默认开缓存,一级缓存是SqlSession级别,二级缓存要手动配。我一开始没注意,测试环境跑批时查出来结果不对,发现是二级缓存没清干净,不同SqlSession之间读到脏数据。医疗数据最怕这个,检验单返回前天的结果要出事故。所以我直接关了二级缓存,靠Redis手动管,key设计成patient:report:{id},过期时间跟着业务走。
还有个坑是N+1查询。association和collection映射方便,但嵌套查询一不小心就发一堆SQL。查科室列表再查每个科室医生数,一页20个科室发了21条SQL,压测直接崩。改成一条JOIN加resultMap的collection嵌套映射,SQL从21条降到1条,响应时间从1.8秒降到90毫秒。思路跟Python里避免循环查库一样,但MyBatis里XML写起来爽,SQL数量容易失控。
AI工具在学MyBatis上意外好使。我把复杂的resultMap配置截图喂给AI,让它解释标签作用,再让它生成从表结构自动生成MyBatis XML的Python脚本。生成的代码不能直接用,但省了大量查文档时间。不过AI生成的SQL偶尔有语法错误,尤其动态SQL的<if>和<foreach>嵌套时,还是得自己过一遍。
这段经历让我想明白:框架没有银弹,关键看场景。SQLAlchemy写起来快,但遇到复杂查询和极致性能要求时,MyBatis那种“SQL在手”的感觉确实爽。医疗数据量大、查询复杂、性能卡得严,MyBatis这种半自动化框架反而更合适。
最后说个有意思的,上周改一个慢查询,EXPLAIN看了半天发现是索引失效,${}和#{}用混了,${}拼接字符串导致全表扫描。改回#{}预编译后,查询从3秒变80毫秒。这种细节在Python的ORM里基本遇不到,因为参数绑定是自动的,但MyBatis给了你自由,也给了你犯错的空间。

评论 0