深度吐槽 hibernate
hibernate 我很久都没有用了,最后一次用应该是 3 年前的一个企业项目,决定采用 hibernate 的并不是我,是我领导,我只是开发者。我所受的罪领导并不知道。正 如我的每个 hibernate 项目那样,每次我都是用的提心吊胆。尽管我从 ejb1.1 到 hiberate,然后再到 jpa 都经历过,这种一脉相承的技术 我了解和应用了有 14 年,但我还是不敢声称精通 OR Mapping,尤其是最近 hibernate 版本又都了些新概念和新 Annotation,让我还觉得我是个 hibernate 新手:OR Mapping 也许就是个 DAO 错误的方向。
让我来吐槽一下 hibernate 这种 DAO 工具,并提一下我认为完美的 DAO 工具。
槽点一 容器设计的败笔。 系统的核心是模型,也就是 JavaBean,使用 hiberante 的项目,JavaBean 被持久化容器劫持这是第一个槽点。尽管对模型操作,在容器的 帮助下,能很快映射到数据库操作,然而,现在越多越多的 DAO 框架都避免设计容器,就算是 JPA 规范,也只声称了是个 API,而不再提持久化容器了,因为 持久化容器已经不得人心了。以下是使用 hibernate 经常出现的问题 (但不限于下面几个) 1 容器内,对模型的操作我不一定得映射到数据库里,可容器会强制 2 对象在容器内,一切操作都很顺利,但出了容器,会有各种 hibernate 异常。须知应用并不只有 hibernate。 3 修改一个对象的属性,必须先从数据库 load 进来,成为容器管理对象,才能修改
槽点二之 hierbnate 能提高生产力? 我早期接触 hb,并没有被所谓的容器托管 Bean 所吸引(上面已经说了,实际上这是个高级陷阱),我只觉得以后添加,修改都只需要调用一下 HB 的 api 就 可以了,就算是查询,也貌似很方便,有 load 的方法。现在看来,这些功能,几乎所有的 dao 框架,所有公司自己的 dao 工具都有,我在 2002 年就做过 最早的 dao 工具,并能自动生成 dao,javabean. 现在,我在 beetl 基础上,做了更好的 beetlsql,也完全具备这种入门级功能。 吐槽 hibenate 并不能提高生产力,是因为其他功能提供的太容易用错和导致效率不高了,以下是 hibernate 效率不高的几个方面(但不限于以下俩个) 1 不可控的生成 sql,每个用过 hibernate 的人都见只有一次 api 调用,可能是 one2many, 也可能是 lazylaod,但控制台满屏的输出 sql 者情况,这导致性能下降,你可以说这是开发人员不精通导致的,可是,HB 为什么要提供这种手段让开人员走到这一步,好的工具应该为程序员提供便利, 阻止程序员犯错。 2 难以调试的 HQL。如果你需要得到数据库专家支持,数据库人员会拒绝你给他的 HQL,他需要的是 SQL,数据库也需要的是 SQL。所幸我项目中没有人打算 给 DBA 培训 HQL 语句(这太疯狂了,DBA 估计会暴动),HQL 在我看来就是一个很鸡肋的功能。如果纯粹是为了跨数据库平台,不同 DAO 框架都有不同方 案,比如 beetlsql 就共用的 sql 语句放一个地方,数据库特定 sql 语句放到指定地方。常规的翻页,序列等特性,通过方言实现类就解决了。
槽点三:annotation 表达力不足, 以 fetch 来说,我有的业务需要 eger 加载,有的业务需要 lazy 加载,hibernate 显然做不到,唯一的解决方法就是加入更多的新 annotation 来表达,如果还不做到,就让 annotation 具备脚本或者 sql 功能。可问题来了,这样的极限方式不就是我们属性的程序语 言 + sql 方式吗。 hiberante 现在是 5.0 也许到了 25.0 版本后,他可能真的是一门语言 + sql 的工具了,但这样有什么意义呢。 我认为 annotation, 最多只能描述表映射就可以了。很多其他框架就是这么做的。如下是一些经常的槽点(但不限于以下三个槽点): 1 fetch 模式 根据业务来的,但 annotation 只能一种,我选用哪种都不合适 2 我的数据库之间表关系并不严格(这常见),导致 hibernate 都启动不了 3 我想敏捷开发,把已经确定的做出来,但 hibernate 要求我有完整的模型,否则,都启动不起来
大部分其他 dao 框架都不会出现上面的问题。
槽点四:程序中的 SQL 是个重要资产,需要维护,但 hibernate 并没有去做。HB 最早是只有 xml 配置文件,作者认为只要通过配置就能完成所有 dao 操作,但是后来发现不行,就又搞了一个 HQL,结果发现 HQL 跟 SQL 完全不能比,最 后支持 Native SQL. 就算这样的演进,但 HB 作者仍然没有意识到 SQL 才是 DAO 的核心, 需要重点维护。 这也是 Mybatis,Beetlsql 框架能让大家接受并喜爱的原因。 通过 Java 拼接 hql 或者 sql 问题不大,无非是把数据库调试好的的几十行 sql 拆开拼接就好了。但这样开发效率不高,更重要的是,维护效率低,一旦业 务有改动,sql 机会不得不重新在 java 里拼接。hibernate 本来应该像 sql 那样提供 sql 拼接,但并没有,反而是 mybatis,beetlsql 在这方便做的很好。
越来越多的人意识到 hibernte 是个问题,从而转用了 mybatis, jfinal,nutzdao,beetlsql 等这样的开源 dao 工具,我认为一个理想的 dao 工具,应该有如下功能是必须的:
1 好的 dao 工具,支持 javabean 模型 2 好的 dao 工具,在 javabean 基础上,不能干涉 javabean 模型 3 支持 sql 的维护,如像 beetlsql 那样通过 markdonw 格式维护 sql,或者像 myabtis 那样通过 xml 维护 4 支持跨数据库平台 5 简单的数据库操作无需用户开发,大部分 dao 工具都能做到这点,比如 beetlsql 支持新增,修改,根据模板修改,根据主键查询,根据模板查询等,至少 40% 的 dao 代码都不需要重写 6 代码生成,比如生成 javabean,生成 dao 代码,生成查询 sql 语句等 8 dao 工具并不能要求数据库完全符合数据库高级范式,也不要求程序完全的 OO。 7 最为重要的是,dao 工具必须是个工具,任由开发人员使用。