Vibe Coding 时代,最好的 Java ORM 是没有 ORM

上周,开源中国一篇《放弃 MyBatis,拥抱新一代 Java 数据访问库》火了。文章推荐了一个叫 dbVisitor 的框架,号称能用”One API Access Any DataBase”——一套 API 访问所有数据库。

我看完的第一反应是:又来?

不是说 dbVisitor 不好。设计思路清晰,技术实现扎实。但我忍不住想:我们真的需要再造一个轮子吗?

越统一,越复杂

dbVisitor 的愿景很美好:统一 MySQL、MongoDB、Elasticsearch、Redis 的访问方式。不再区分”这是 ORM”还是”这是 Client”,所有数据访问都走一个入口。

听起来很棒。但仔细想想,这不就是另一个版本的”大一统”梦想吗?

本来想省事,结果更累。

dbVisitor 的路子本质上没变:用一层抽象来屏蔽底层差异。但抽象是有代价的。

当你需要用 Elasticsearch 的聚合查询时,dbVisitor 的”统一 API”还能覆盖吗?当你需要 Redis 的原子操作时,还是得”穿透”到底层 SDK。作者自己也承认了这个问题:

“当统一 API 无法满足特殊需求时,dbVisitor 允许通过 unwrap 机制’穿透’到底层驱动。”

所以这个”统一”其实是打了折扣的。简单场景统一,复杂场景还是得回到原点。

另一条路:把 ORM 做到极致

有人选择统一,有人选择深耕。

去年 Jimmer 这个框架挺火,号称”JVM 中最先进的 ORM”。它的思路和 dbVisitor 完全不同:不追求统一所有数据源,而是把关系型数据库的 ORM 做到极致。

Jimmer 确实解决了一些老大难问题。N+1 查询?它用 SQL DSL 在编译期就规避了。对象图的保存?它能自动 diff,只更新变化的部分。实体类太臃肿?它用接口定义实体,编译时生成实现。

本来我和群里的大佬约了稿,想让他深入聊聊 Jimmer。但后来仔细想了想,觉得这个话题可能太小众了——毕竟是个新框架,用的人不多,大家可能不太感兴趣。所以就没继续写下去。

不过这不妨碍我们看看它的设计思路。

1
2
3
4
5
6
7
8
9
10
11
12
// Jimmer 的查询方式:编译期类型安全
List<Book> books = sqlClient
.createQuery(table)
.where(table.name().like("Java%"))
.select(
table.fetch(
Fetchers.BOOK_FETCHER
.allScalarFields()
.store(Fetchers.BOOK_STORE_FETCHER.name())
)
)
.execute();

Jimmer 解决的是”ORM 不够好”的问题,方案是”做一个更好的 ORM”。代价呢?一套新 DSL,一套新注解,一套新的思维模型。你得先花几天学会它,才能享受它的好处。

值不值?看情况。但我总觉得,方向可能错了。

GraphQL 也是类似的路子。Spring 官方都出了 Spring for GraphQL,它解决的是”前端要什么数据,后端就给什么数据”的问题。不多不少,精准投喂。

听起来很美好。但代价是什么?你得定义 Schema,写 Resolver,处理 N+1(对,GraphQL 也有 N+1 问题),还得学一套新的查询语法。前后端都得改造,工作量不小。

Jimmer 和 GraphQL,一个在 ORM 层做文章,一个在 API 层做文章。它们都在试图用更复杂的工具解决复杂的问题。

但我想问一个问题:如果 SQL 本身不再是痛点了呢?

ORM 的老本,还能吃多久?

说句公道话,ORM 不是一无是处。

工程化场景下,ORM 确实有它的价值。统一的 API 让团队协作更顺畅,代码风格一致,新人上手快。异构数据库切换?改个配置文件,理论上代码不用动。事务管理、连接池、缓存,这些脏活累活 ORM 都帮你包了。

十年前,这些是实打实的优势。

当 AI 抹平了 SQL 的编写门槛时,ORM 那些复杂的 API 映射反而成了开发者和数据库之间多余的”中间商”。

工程化:AI 生成的 SQL 风格比人写的还统一。你让 Claude 写十条查询,它给你的代码风格一定是一致的。团队协作的问题?Skills 模板统一一下就行。

异构数据库切换:说实话,你这辈子换过几次数据库?从 MySQL 换到 PostgreSQL?大多数项目从立项到下线,数据库都没换过。为了一个”可能永远不会发生”的场景,背上 ORM 的学习成本和性能开销,值得吗?

事务和连接池:这些跟 ORM 没关系。Spring 的 @Transactional 配合 JdbcClient 一样能用,HikariCP 连接池也不挑客户端。

ORM 的老本,在 AI 时代越来越不够吃了。

JdbcClient:轻量才是王道

说到这里,就不得不提 Spring Boot 3.2 引入的 JdbcClient。

JdbcClient 是 Spring 团队对数据访问的”减法”尝试。它不是 ORM,甚至算不上框架,就是一个简洁的 JDBC 封装。来看个对比:

1
2
3
4
5
6
7
8
9
// MyBatis 方式:需要定义 Mapper 接口 + XML 或注解
@Mapper
public interface UserMapper {
@Select("SELECT * FROM sys_user WHERE username = #{username}")
SysUser findByUsername(String username);
}

// 调用
SysUser user = userMapper.findByUsername("lengleng");
1
2
3
4
5
6
7
// JdbcClient 方式:一行搞定
SysUser user = jdbcClient
.sql("SELECT * FROM sys_user WHERE username = :username")
.param("username", "lengleng")
.query(SysUser.class)
.optional()
.orElse(null);

看起来代码量差不多?差别在细节。

JdbcClient 不需要额外定义 Mapper 接口,少一个文件就少一份心智负担。SQL 直接写在调用的地方,不用在 XML 和 Java 之间跳来跳去。链式 API 写起来顺手,IDE 提示也跟得上。最关键的是——AI 生成的 SQL,直接贴进来就能跑。

Vibe Coding 场景下,这个优势太明显了。你让 AI 写一段查询逻辑,它给你的就是原生 SQL。用 JdbcClient?无缝接入。用 MyBatis?还得把 SQL 搬到 XML 里,再写个 Mapper 接口。

多了一道工序,开发体验就差了一截。

最好的 ORM 是没有 ORM

说一句可能会得罪人的话:在 AI 时代,最好的 ORM 是没有 ORM。

ORM 的历史使命是当”翻译官”——帮你把对象映射成 SQL。它存在的原因很简单:我们不擅长写 SQL,或者说写 SQL 太慢了。

但 AI 是更好的翻译官。它能写 SQL,能写 Java,能写任何你想要的代码。更重要的是,AI 生成的 SQL 是透明的,你能看到、能调试、能优化。ORM 生成的 SQL 呢?藏在黑盒里,出了问题你得猜。

所以我的建议是:让 AI 写 SQL,它比任何 ORM 都懂数据库方言;用 JdbcClient 执行,够轻够快;保持代码透明,出问题一眼就能看出来。

这不是开倒车。新工具能更好地解决老问题,旧工具自然该让位了。

当然,如果你的项目已经深度绑定了 MyBatis 或 JPA,没必要急着换。但如果是新项目,不妨试试”薄映射”的思路:AI + JdbcClient。简单,直接,够用。

毕竟,最好的代码不是写出来的,是不用写的。