返回介绍

JDBC 后传

发布于 2025-01-22 00:38:52 字数 6013 浏览 0 评论 0 收藏 0

抱怨

JDBC 出现以后, 以其对数据库访问出色的抽象, 良好的封装, 特别是把接口和具体分开的做法, 赢得了一片称赞。

乘着 Java 和互联网的东风, JDBC 在风口飞了起来, 无数的程序开始使用 JDBC 进行编程, 访问数据库村的数据库, 在数据库村,无论是大佬 Oracle, 还是小弟 Mysql 都赚的盆满钵满。

所谓物极必反, JDBC 的代码写得多了, 它的弱点就暴露出来了, 很多码农抱怨道:“JDBC 是在是太 Low 了”。

消息传到 Tomcat 村, Java 简直不相信自己的耳朵: “什么? JDBC 还很 low ? 看来那帮码农没有用 socket 访问过数据库吧?! 那才叫 low . ”

Tomcat 说 : “你是个标准的制定者, 写代码太少了,太不接地气了, 你看看这样的代码: ”

Java 把代码拿过来一看, 不由的倒吸了一口凉气: “ 代码怎么这么长啊, 似乎是有那么一点问题, ‘ 噪声 ’似乎太多了, 把业务代码全给淹没了”

Tomcat 说:”看来你也是个明白人啊, 为了正确的打开和关闭你定义的 Connection , Statement, ResultSet 需要花很多功夫, 再加上那些异常处理, 一个 50 多行的程序, 真正做事的也就那么 10 几行而已, 这些琐碎代码太烦人了, 所以大家抱怨很 low 啊。 ”

Java 表示同意: “不错, 可以想象, 如果代码中有大量这样的代码, 码农会抓狂的, 不过,” Java 突然想到了些什么 , “其实这不是我的问题, 码农们抱怨错人了, 我作为一门语言, 所能提供的就是贴近底层(socket) 的抽象, 这样通用性最强。 至于码农想消除这些重复代码, 完全可以再封装, 再抽象, 再分层啊

Tomcat 想想也是, 在计算机世界里, 每个人都有分工, 不能强求别人做不喜欢也不擅长的事情, 看来这件事错怪 Java 了。

JDBCTemplate

Java 预料的不错, 稍微有点追求, 不愿意写重复代码的码农都对 JDBC 做了封装, 例如写个 DBUtil 的工具类把打开数据库连接, 发出查询语句都封装了起来。

码农的抱怨也渐渐平息了。

有一天, 有个叫 JDBCTemplate 的人来到了 Tomcat 村找到了 Java , 他自称是 Rod Johnson 派来专门用于解决 JDBC 问题的, 他提供了一个优雅而简洁的解决方案。

(注: Rod Johnson 就是 Spring 最初的作者)

JDBCTemplate 说: “尊敬的 Java 先生, 感谢您发明了 JDBC, 让我们可以远程访问数据库村, 您也听说了不少对 JDBC 的抱怨吧, 我的主人 Rod Johnson 也抱怨过, 不过他在大量的编程实践中总结了很多经验, 他认为数据库访问无外乎这几件事情:

指定数据库连接参数

打开数据库连接

声明 SQL 语句

预编译并执行 SQL 语句

遍历查询结果

处理每一次遍历操作

处理抛出的任何异常

处理事务

关闭数据库连接”

“我的主人认为” JDBCTemplate 说, “开发人员只需要完成黑体字工作就可以了,剩下的事情由我来办“

“你们主人的总结能力很强, 把一个框架应该做的事情和用户应该做的事情区分开了 ” Java 说

JDBCTemplate 看到 Java 态度不错, 赶紧趁热打铁: “ 我给你看个例子:”

Java 和之前那个传统的 JDBC 比较了一下, JDBCTemplate 的方式的确是把注意力放到了业务层面: 只关注 SQL 查询, 以及把 ResultSet 和 User 业务类进行映射, 至于如何打开/关闭 Connection, 如何发出查询,JDBCTemplate 在背后都给你悄悄的完成了, 完全不用码农去操心。

“你在 JDBC 上做了不错的抽象和封装” Java 说, “但是我还不明白 JDBCTemplate 怎么创建出来的”

“这很简单, 你可以直接把它 new 出来, 当然 new 出来的时候需要一个参数, 就是 javax.sql. DataSource, 这也是你定义的一个标准接口啊”

"当然, 我主人 Rod Johnson 推荐结合 Spring 来使用, 可以轻松的把我‘注入’到各个你需要的地方去"。

“明白了, 你们主人这是要推销 Spring 啊, 那是什么东西? ”

“简单的说,就是一个依赖注入和 AOP 框架, 功能强大又灵活。 具体的细节还得让我主人亲自来给您介绍了 ”

“好吧, 不管如何, 我看你用起来还不错, 可以向大家推荐一下。”

O/R Mapping

JDBCTemplate 这样对 JDBC 的封装 , 把数据库的访问向前推进了一大步, 但是 Tomcat 村和数据库村的很多有识之士都意识到: 本质的问题仍然没有解决!

这个问题就是面向对象世界和关系数据世界之间存在的巨大鸿沟。

Tomcat 村的 Java 程序都是面向对象的: 封装、继承、多态, 对象被创建起来以后, 互相关联, 在内存中形成了一张图。

数据库村的关系数据库则是表格: 主键,外键, 关系运算、范式、事务。 数据被持久化在硬盘上。

ResultSet 依然是对一个表的数据的抽象和模拟: rs.next() 获取下一行, rs.getXXX("XX") 访问该行某一列。

把关系数据转化成 Java 对象的过程, 仍然需要码农们写大量代码来完成。

现在码农的呼声越来越高, 要把这个过程给自动化了。 他们的要求很清晰: 我们只想用面向对象的方式来编程, 我们告诉你 Java 类、属性 和数据库表、字段之间的关系, 你能不能自动的把对数据库的增删改查给实现了

他们还把这个诉求起了一个很洋气的名称: O/R Mapping (Object Relational Mapping)

Java 自然不敢怠慢, 赶紧召集 Tomcat 村和数据库村开了一次会议, 确定了这么几个原则:

1. 数据库的表映射为 Java 的类(class)

2. 表中的行记录映射为一个个 Java 对象

3. 表中的列映射为 Java 对象的属性。

但是光有这几个原则是远远不够的, 一旦涉及到实际编程, 细节会扑面而来:

1. Java 类的粒度要精细的多, 有时候多个类合在一起才能映射到一张表

例如下面的例子, User 类 的 name 属性其实是也是一个类, 但在数据库 User 表中, firstName, middleName, lastName 却是在同一张表中的。

2. Java 的面向对象有继承, 而数据库都是关系数据, 根本没有继承这回事!

这时候可选的策略就很多了, 比如

(1) 把父类和子类分别映射到各自的 Table 中, 数据会出现冗余

(2) 把父类的公共属性放到一个 Table 中, 每个子类都映射到各自的 Table 中, 但是只存放子类自己的属性。子类和父类的表之间需要关联。

(3) 干脆把父类和子类都映射到同一张 Table 中, 用一个字段(例如 Type)来表明这一行记录是什么类型。

3. 对象的标识问题

Java 中使用 a==b 或者 a.equals(b) 来进行对象是否相等的判断, 而数据库则是另外一套:使用主键。

4. 对象的关联问题

在 Java 中, 一个对象关联到另外一个或者一组对象是在是太常见了, 双向的关联(也就是 A 引用 B , B 反过来也引用了 A )也时常出现, 而在数据库中定义关联能用的手段只剩下外键和关联表了。

5. 数据导航

在 OOP 中, 多个对象组成了一张网, 顺着网络上的路径, 可以轻松的从一个对象到达另外一个对象。 例如: City c = user.getAddress().getCity();

在关系数据库中非得通过 SQL 查询, 表的连接等方式来实现不可。

6. 对象的状态

在 OOP 中, 对象无非就是创建出来使用, 如果不用了,就需要回收掉, 但是一旦扯上数据库, 势必要在编程中引入新的状态,例如“已经持久化”

......

(注: 本来想讲 Hibernate, 但是限于篇幅, 实在是无法展开讲细节, 这几个问题是 Hibernate 官网上提到的, 是 O/R Maping 的本质问题)

这些细节问题让 Java 头大, 他暗自思忖: " 还是别管那些码农的抱怨, 我还是守住 JDBC 这一亩三分地吧, 这些烦人的 O/R Mapping 问题还是让别人去处理好了。 "

O/R Mapping 的具体实现就这么被 Java 搁置下了。

Hibernate 和 JPA

随着时间的推移,各大厂商都想利用 Java 赚钱, 联合起来搞了一个叫 J2EE 的规范, 然后疯狂的推行自己的应用服务器(例如 Weblogic, Websphere 等等),还搭配着硬件销售, 在互联网泡沫时代赚了不少钱。

J2EE 中也有一个叫 Entity Bean 的东西, 试图去搞定 O/R Mapping , 但其蹩脚的实现方式被码农们骂了个狗血喷头。

转眼间, 时间到了 2001 年, Tomcat 告诉 Java 说: “听说了吗? 现在很多码农都被一个叫 Hibernate 的东西给迷住了”

"冬眠(Hibernate) ? 让内存中的数据在数据库里冬眠, 这个名字起的很有意境啊 , 我猜是一个 O/R Mapping 工具吧"

"没错, 是由一个叫 Gavin King 的小帅哥开发的, 这个框架很强悍, 它实现了我们之前讨论的各种烦人细节, 大家都趋之若鹜, 已经成为 O/R Mapping 事实上的标准, Entity Bean 已经快被大家抛弃了。 "

“没关系, Entity Bean 从 1.0 开始就是一个扶不起的阿斗, 我已经想通了, 我这里只是指定标准, 具体的实现让别人去做。 既然 Hibernate 这么火爆, 我们就把 Gavin King 招安了吧 ”

“怎么招安? ”

“让小帅哥过来领导着大家搞一个规范吧, 参考一下 Hibernate 的成功经验 , 他应该会很乐意的。 ”

不久以后, 一个新的 Java 规范诞生了, 专门用于处理 Java 对象的持久化问题, 这个新的规范就是 JPA(Java Persistence API), Hibernate 自然也实现了这个规范, 几乎就是 JPA 的首选了。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文