持久层框架的评价标准:只有一个

持久层框架的评价标准:只有一个

你得知道你在跟谁打交道。

写代码十几年,我见过无数持久层框架的选型争论。Hibernate 粉丝说"不用写 SQL 就是爽",MyBatis 信徒说"SQL 控制权最重要",JOOQ 拥趸说"类型安全才是未来"。

争论到最后,谁也说服不了谁。

直到有一天,我看到这样一段代码:

java 复制代码
@Repository
public class UserDao extends BaseDao<User> {
    // 空的,什么都没写
}

就这么一个空类,单表 CRUD、分页、按 ID 查询、批量操作,全有了。

然后我又看到了条件类的写法:

java 复制代码
@Setter
@Getter
public class UserCond extends BaseCondition {
    private String userName;
    private Integer ageMin;
    private Integer ageMax;
    private Long deptId;

    @Override
    protected void addCondition() {
        add("AND user_name LIKE ?", userName, 3);
        add("AND age >= ?", ageMin);
        add("AND age <= ?", ageMax);
        add("AND dept_id = ?", deptId);
    }
}

再看到联表查询的写法:

java 复制代码
private static final String JOIN_SQL = """
    SELECT u.*, d.dept_name
    FROM sys_user u
    JOIN sys_dept d ON u.dept_id = d.dept_id
    """;

public Page<UserVO> pageJoin(UserCond cond) {
    return page(JOIN_SQL, cond, UserVO.class);
}

同一个 UserCond,单表用、联表用,条件拼接方式完全一致。没有任何切换成本。

整个持久层工具的核心代码加起来,不到 1500 行。

然后我回头看了看 MyBatis 的源码------几万行。MyBatis-Plus------几万行。Hibernate------几十万行。

问题来了:这 1500 行代码,跟那几十万行代码,解决的是不是同一个问题?

如果是,那那些几十万行的框架,到底"多"了些什么?

市面上常见的评价标准,都跑偏了

大多数人评价一个持久层框架,看的是这些东西:

  • 功能列表:支持多少种数据库?有没有分页插件?有没有代码生成器?
  • 生态大小:有多少人在用?有多少扩展插件?文档多不多?
  • 大厂背书:是不是 Apache 项目?有没有大厂在使用?
  • 封装程度:它帮我写了多少代码?我是不是少写了很多行?

这些标准听起来合理,但仔细一想------它们全都是在问"这个框架给了我什么",而不是在问"这个框架让我失去了什么"。

一个框架给了你 100 个功能,如果其中 99 个你本来就不需要,那这 99 个功能就是噪音。你不仅没赚到,还亏了------因为你得花时间去知道"自己不需要它们"。

真正的评价标准:SQL 浓度

我提出一个朴素的标准,大家听听看:

看代码里的 SQL 浓度。SQL 浓度越高,说明框架越好;噪音越高,说明框架越垃圾。

什么叫 SQL 浓度?就是你写的代码里,真正属于 SQL 的那部分占多少。剩下的那部分------不管叫配置、叫注解、叫 Wrapper、叫 DSL------都是噪音。

拿这个标准去看市面上的框架:

MyBatis XML:

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...>
<mapper namespace="com.gzz.sys.user.UserMapper">
    <select id="queryList" resultMap="userMap">
        SELECT * FROM sys_user WHERE 1=1
        <if test="name != null and name != ''">
            AND name LIKE CONCAT('%', #{name}, '%')
        </if>
    </select>
</mapper>

SQL 浓度:不到 30%。剩下的全是 XML 头、命名空间、标签、resultMap。你写了 10 行代码,其中 7 行是在伺候框架。

MyBatis-Plus LambdaWrapper:

java 复制代码
lambdaQuery()
    .eq(User::getAge, 18)
    .like(User::getName, "张")
    .list();

SQL 浓度:0%。你根本看不见 SQL。你要靠脑补去猜它会生成什么。

而且,更致命的问题来了------单表一时爽,联表火葬场。

单表查询确实爽,链式调用一行搞定。但一旦你的查询涉及到两张表以上的 JOIN、子查询、聚合函数、UNION,Wrapper 立马就露馅了。你只能退回去写 XML 或者 @Select 注解。然后你的项目里就出现了两套条件构造方式:单表用 Wrapper,联表写 XML。你前面学的那些 .eq().like() 在复杂场景下全是废的。

Hibernate HQL:

java 复制代码
"from User where age = :age and name like :name"

SQL 浓度:50%。但你还是看不见最终发给数据库的 SQL 是什么。而且 HQL 只是 SQL 的一个子集,很多数据库特有的功能你根本用不了。

SimpleDAO 方案(你的框架):

java 复制代码
// 条件类------SQL 浓度 100%
@Override
protected void addCondition() {
    add("AND user_name LIKE ?", userName, 3);
    add("AND age >= ?", ageMin);
    add("AND dept_id = ?", deptId);
}

// 单表查询
userDao.list(cond);

// 联表查询------同一个 cond,同一个方法,只是多了一个 SQL 字符串
String sql = "SELECT u.*, d.dept_name FROM sys_user u JOIN sys_dept d ON u.dept_id = d.dept_id";
userDao.page(sql, cond, UserVO.class);

关键点来了:单表和联表用的是同一套 BaseCondition,没有任何切换成本。 你学的 add 方法,单表能用,联表也能用。学一次,用一辈子。

噪音从哪里来?

所有的噪音,本质上是同一个东西:你为了"伺候框架"而写的代码。

  • MyBatis 的 XML 头、namespace、resultMap,是噪音。你写它们不是为了解决业务问题,是为了让框架能找到你的 SQL。
  • Wrapper 的 .eq().like().ge(),是噪音。你写它们不是因为 SQL 更清晰,是因为框架不允许你直接写 SQL。而且 Wrapper 的噪音有个特点:它只在单表场景下"看起来"低噪音,一旦遇到联表,它连用都用不了,你被迫回到 XML 里写标签------噪音一下子暴涨。
  • 分页插件、数据权限插件的配置,是噪音。你写它们是因为框架没有提供原生支持,你得用插件去"补"。
  • 代码生成器生成的模板代码,是噪音。你写它们是因为框架要求你写,你不写就没法跑。

你仔细看:这些噪音,没有一行是在解决业务问题。它们全是在解决"框架带来的问题"。

框架制造了一个黑盒,然后告诉你:你得学我这一套规则,才能在黑盒上开个洞。你学的那些规则、写的那些配置、配的那些插件------框架管这叫"生态丰富",实际上它只是"补丁生态"。

而你的 BaseDao 呢?它只是一个空类。你继承它,单表 CRUD 全有了。你想联表?自己写 SQL,用 BaseSql 的方法执行。没有任何多余的配置,没有任何多余的注解,没有任何多余的插件。

你写的每一行代码,都在解决业务问题。没有一行是在"伺候框架"。

你得知道你在跟谁打交道

所有持久层框架,本质上都在做同一件事:帮你把数据从数据库里拿出来,放进去。

但框架们对待这件事的态度,分成了两派:

一派认为:SQL 太底层了,我们要把它封装起来,让开发者不用写 SQL。

于是有了 Hibernate,有了 JPA,有了各种 ORM。它们试图用对象模型覆盖关系模型。

另一派认为:SQL 还是有价值的,但我们要用一套"更优雅"的方式来写它。

于是有了 MyBatis 的 XML 标签,有了 JOOQ 的 DSL,有了各种 Wrapper。

这两派的共同点是什么?

它们都在你和你真正要打交道的东西之间,插了一个中间人。

你本来要跟数据库打交道。现在你得先跟 Hibernate 打交道,再让它去跟数据库打交道。你本来要写 SQL。现在你得先写 HQL,再让 Hibernate 翻译成 SQL。

这个中间人如果靠谱也就算了。问题是------

  • 你写的 HQL,它翻译出来的 SQL 可能根本不是你想的那样。
  • 你写的 LambdaWrapper,它生成的 SQL 可能没走索引。
  • 你写的 XML,那个 <if> 标签可能漏了一条条件。

你得知道你在跟谁打交道。你在跟数据库打交道。你在跟 SQL 打交道。

你写的每一行代码,最终都要变成 SQL,发给数据库。既然如此,为什么要在中间加一层"翻译官"?这个翻译官既不比你聪明,也不比你快,它只是让你多了一道"猜它翻译得对不对"的步骤。

那不用 MyBatis,用什么?

兄弟,你这个问题,你的 simple-dao 就是答案。

这个框架的核心就是三件套:

BaseCondition ------ 拼条件。你用 add("AND age >= ?", ageMin) 手写 SQL 片段,框架帮你收集参数。单表用它,联表也用它,ON 条件用它,EXISTS 子查询也用它。学一次,用一辈子。

BaseDao ------ 单表对象化。你继承它,就获得了完整的单表 CRUD、分页、批量操作能力。自动填充审计字段(createTime、createBy、updateTime、updateBy),自动处理逻辑删除(dr)。就一个空类,啥都不用写。

BaseSql ------ 执行 SQL。你写任何 SQL(单表、联表、子查询、CTE、窗口函数),用 list()page()row()field()columns() 五种方法覆盖所有结果形态。你的 SQL 浓度 100%,框架不加任何中间层。

你学这一个框架,就等于学会了所有场景下的数据库访问。没有两套语法,没有切换成本,没有学习曲线。

总结

持久层框架只有一个评价标准:

你写的代码里,SQL 浓度有多少?

  • SQL 浓度 100%:你在直接跟数据库打交道。你写的每一行代码都在解决业务问题。单表联表用同一套条件构造,没有任何切换成本。
  • SQL 浓度 50%:你一半时间在写业务 SQL,另一半时间在学框架的规则。而且联表查询时,你之前学的那套 Wrapper 语法基本作废。
  • SQL 浓度 0%:你完全在跟框架打交道。SQL 长什么样,你得靠猜。联表查询?想都别想。

你要先想清楚你在跟谁打交道。

你是在跟 MyBatis 打交道,还是在跟 SQL 打交道?

你是在跟 Hibernate 打交道,还是在跟数据库打交道?

你是在跟 LambdaWrapper 打交道,还是在跟你想要的数据打交道?

想清楚这个问题,你就知道该怎么选了。

如果有一天你发现,你写的大部分代码不是在"干活",而是在"伺候框架"------那你就该换框架了。

这就是持久层框架的唯一评价标准。没有之一。

写在最后:SQL 浓度,是最好的面试题

你去面试的时候,面试官问你:"你怎么评价 MyBatis 和 MyBatis-Plus?"

你就问他一句话:

"你们项目里的代码,SQL 浓度是多少?"

如果对方愣住了,说明他从来没从这个角度想过问题。

如果对方说"我们用了 MyBatis-Plus 的 Wrapper,SQL 都是框架生成的,不用写 SQL",你就知道他们的项目里 SQL 浓度接近 0%。联表查询大概率全靠 @Select 注解或者 XML 手写,Wrapper 只在单表场景下自娱自乐。

如果对方说"我们用的是 SimpleDAO,条件继承 BaseCondition,SQL 完全手写,单表和联表用同一套条件,SQL 浓度接近 100%",那你就知道,这帮人懂行。

这个标准之所以有效,是因为它不问"你用什么框架",它问的是"你的代码跟数据库之间隔了几层"。

隔得越少,离本质越近。

离本质越近,噪音越少。

噪音越少,代码越干净。

这就是唯一的标准。没有之一。

相关推荐
孔明click331 小时前
Sa-Token v1.46.0 发布 🚀,来看看有没有令你心动的功能!
java·sa-token·开源·springboot·权限认证
m0_587383001 小时前
智慧场馆解决方案实战指南:从系统架构到落地部署全解析
java·spring boot·架构·系统架构
ZC跨境爬虫1 小时前
LeetCode 13. 罗马数字转整数(多解法详解 + Java Python 实现)
java·python·leetcode
省长2 小时前
Sa-Token v1.46.0 发布 🚀,来看看有没有令你心动的功能!
java·后端·开源
LayZhangStrive2 小时前
融360 一面
java·面试·后端开发
城管不管2 小时前
重生——第十次面试之开源中国一面挂
java·linux·开发语言·算法·面试·职场和发展·开源
Java小白笔记2 小时前
Windows系统免软件命令激活
java·网络·人工智能·windows·ai·ai编程
爱敲键盘的猴子3 小时前
深入理解 Java HashMap
java·hashmap
霸道流氓气质3 小时前
Java开发者AI编程常用MCP、Skills、Rules全景汇总
java·开发语言·ai编程