当 Java 1.0 于 1996 年推出时,语言和互联网都与今天大不相同。当时,网络主要是静态的,而 Java 承诺通过注入交互式游戏和动画来为网络注入活力,这一承诺极具前景。根据 1995 年写给《连线》杂志的 David Banks 的说法,Java 是自 Netscape 以来最热门的技术。
为了更好地理解,Java 的起源可以追溯到 1990 年,当时 Sun Microsystems 在消费市场中的定位举步维艰。在那个时期,他们开发了 Oak,一种旨在实现平台无关、轻量级且非常适合网络环境的编程语言。他们的首次尝试是将 Oak 商业化,用于交互式电视。
到 1994 年,互联网开始普及,Sun 公司认识到 Oak 是其完美的应用程序。与传统软件不同,Oak 允许小程序(小型可移植程序)在任何带有解释器的机器上运行,使其非常适合网络应用程序。Oak 被重新命名为 Java,其解释器被命名为 Java 虚拟机,并创建了一个原型浏览器 HotJava 来展示其功能。
然而,Java 1.0 缺乏标准化的数据库连接。当时互联网仍处于起步阶段,数据库主要应用于企业级应用而非基于网络的软件。因此,Java 的初始设计重点在于创建能够在不同平台上无缝运行的应用程序,而非与后端数据存储系统集成。考虑到当时的背景——数据库领域由 Oracle 7、IBM DB2、Sybase SQL Server 和 Informix 等重型关系型数据库系统主导。这些系统是为传统客户端-服务器架构和企业工作负载设计的,具备复杂的交易处理能力和查询优化器。虽然存在 ObjectStore 和 GemStone 等面向对象数据库,但它们仍属于小众产品,主要用于专门的工程和电信应用。"网络规模"数据库的概念还有数年时间才会出现。
Java 的跨平台性和架构中立设计使其对程序员和企业都具有吸引力。1997 年,在 IBM 工作的 Eli Javier 写信给多伦多的用户组杂志,表示程序员喜爱 Java 是因为它是第一个真正的网络编程语言,而企业喜爱它是因为它可以通过简化应用程序的实施和分发来帮助他们降低成本,因为它可以在任何地方运行,并且可以从中央服务器部署。
就连 IBM 也在 1996 年 Java 1.0 发布后不久,认识到 Java 是网络计算的基础。这一转变在 1997 年得到公开强化,当时 IBM AS/400 部门的总经理比尔·齐特勒明确表示,Java 是 AS/400 业务在网络计算中的关键使能者。
1996年JDBC(Java DataBase Connectivity)诞生
尽管 Java 被迅速采用,但它需要一个统一的方式来与数据库交互。如果没有标准,开发者必须编写特定数据库的代码,这威胁到了 Java 的可移植性。为此,Sun Microsystems 在 Java 1.0 发布后的三个月内推出了 Java 数据库连接 API(JDBC)。受 Microsoft 的 ODBC 启发,JDBC 允许应用程序使用单一接口与数据库交互。到 1996 年年中,JDBC 1.0 最终确定,标志着向企业计算迈出了重要一步。
借助 JDBC,Java 不再仅仅是 applet 和交互式 Web 应用程序的语言,它现在成为企业软件开发的一个可行选项。到 20 世纪 90 年代末,像 Oracle、IBM、Sybase、SAS 和 Borland 等主要数据库厂商已经全面拥抱 Java,并为他们的数据库提供了官方的 JDBC 驱动程序。
虽然 JDBC 是一个突破,但它并非完美解决方案——随着 Java 应用程序的复杂性增加,开发者开始遇到限制。开发者不得不编写大量重复代码来执行简单查询。每次数据库操作都需要手动管理连接、语句和结果集。同时,异常处理既冗长又繁琐,需要使用 try-catch-finally 块进行正确的清理。
对象-关系映射不匹配的弊端开始显现。数据库表和对象是两种截然不同的数据存储介质。关系型数据库通过关系和约束来关注数据的规范化和完整性,而面向对象编程则强调封装、继承和多态。这种根本性的脱节意味着开发者必须不断在这两种范式之间进行转换。具有丰富层次结构和复杂关系的对象必须被扁平化为表格,而规范化的数据库模式则必须被重新组装成相互连接的对象图。在一个世界中的简单概念在另一个世界中变得复杂——Java 中的一个基本继承层次结构可能需要在数据库中通过多个连接表来实现,而一个简单的数据库视图可能需要多个相互关联的类来在对象世界中正确表示。这种阻抗不匹配不仅使开发更加复杂,还影响了性能,因为每次范式之间的转换都会给数据库操作增加额外开销。
1998年EJB(Enterprise JavaBeans)诞生
为了应对这些挑战,J2EE(Java 2 企业版)在 1998 年引入了企业 JavaBeans(EJB)。正如 Cliff Berg 在 1999 年给 Info World 写信中所说,EJB 的主要目标是简化企业应用开发,让软件开发者能够专注于业务逻辑,而不是构建自定义的基础设施。EJB 通过内置的事务管理、安全和可扩展性简化了企业开发。
该模型区分了不同类型的 Bean:会话 Bean,用于管理业务逻辑和用户交互;实体 Bean,用于表示持久化数据。EJB 的一个主要创新是容器管理持久化(CMP),它允许数据库交互由应用服务器自动处理,而无需开发者编写显式的 SQL 查询。
通过 CMP,开发者可以定义表示数据库记录的实体 Bean,而 EJB 容器会自动处理这些对象的持久化、更新和检索。这不仅减少了样板代码的量,还提高了数据库可移植性,因为应用程序不再需要与特定的 SQL 语法或数据库供应商紧密耦合。
EJB 还引入了声明式事务管理,这是对传统数据库事务处理的重要改进。它不再需要开发者手动管理事务(如在代码中调用 commit() 和 rollback()),而是允许通过部署描述符以声明方式配置事务。
EJB 旨在解决的另一个数据库相关挑战是连接池。建立数据库连接是一项耗时的操作,为每个请求打开新的连接会导致严重的性能瓶颈。
但尽管 EJB 的数据库管理方法取得了进步,但它也存在问题。实体 Bean 模型常因其性能低效而受到批评,特别是在处理大规模持久化方面。CMP 虽然方便,但引入了显著的开销,因为容器必须动态生成 SQL 并在后台管理数据库操作。有时开发者发现,为了性能调优,需要使用 Bean 管理持久化(BMP),即显式编码数据库操作。
2001年Hibernate诞生
因 EJB 的复杂性而感到沮丧,Gavin King 于 2001 年开发了 Hibernate,这是一个对象关系映射(ORM)框架。他对 Hibernate 的目标是创建一个开源的对象关系映射(ORM)框架,提供透明的持久化,允许开发者使用普通的 Java 对象(POJOs),而不是管理手动 SQL 查询和数据库事务。
与 JDBC 不同,在 JDBC 中,数据库查询作为字符串嵌入在代码中,Hibernate 引入了一种声明式映射系统,允许开发人员在 XML 配置文件中定义数据库关系。这种方法将数据库逻辑与应用程序代码分离,使得在不破坏应用程序逻辑的情况下更容易修改模式。
Hibernate 最显著的贡献之一,正如 Mario Aquino 在 2003 年所写的那样,是通过映射配置实现了一对一、一对多和多对一的关系,从而消除了开发人员手动处理代码中的连接和外键的需要。此外,Hibernate 支持懒加载、级联删除和外连接抓取,允许应用程序通过减少与数据库的往返次数来优化数据库交互。
Hibernate 的另一个主要优势是代码生成和自动化。Hibernate 可以根据对象关系映射定义生成 Java 源文件。这消除了传统 JDBC 应用中所需的大部分手动编码。与 Hibernate 集成的工具(如 Middlegen)甚至可以分析数据库模式并自动生成 Hibernate 映射文件。相比之下,EJB 实体 Bean 需要手动部署描述符和冗长的 XML 配置,这使得它们难以维护和部署。
为了进一步简化应用架构,Hibernate 还引入了一种轻量级且灵活的事务模型。它提供了内置的事务管理,允许开发人员在不直接管理 JDBC 事务的情况下持久化、更新和删除对象。这与 EJB 的容器管理事务形成了鲜明对比,后者迫使开发人员必须在 Java EE 服务器的约束下工作。通过 Hibernate,事务可以通过编程方式或声明式进行处理,提供了更多的控制和灵活性。
到 2003 年,Hibernate 已经成为数据持久化的首选替代方案,取代了 EJB 实体 Bean。它的成功影响了 Java 的官方 ORM 标准。
2006年JPA(Java Persistence API)规范制定
2006 年,鉴于 Hibernate 等 ORM 框架的成功,Java 社区进程(JCP)成立了 JSR 220,该规范将 Java 持久化 API 作为 EJB 3.0 的一部分引入,而 EJB 3.0 又是 Java EE 5 的一部分。
JPA 标准化了 ORM 的不同实现,如 Hibernate、TopLink 和 JDO。它用注解取代了冗长的 XML 配置,引入了 Java 持久化查询语言(JPQL),并允许开发者使用轻量级的 POJO 代替重量级的实体 Bean。JPA 迅速使 EJB 实体 Bean 过时。
注解取代了 XML 配置的需求,使得持久化映射更加清晰。EJB 2.1 需要冗长的 XML 描述符来定义实体映射,但通过 JPA,像@Entity、@Id 和@OneToMany 这样的简单注解使得定义持久化规则变得容易得多。此外,JPA 引入了 Java 持久化查询语言(JPQL),这是一种面向对象的查询语言,改进了传统 SQL 和有限的 EJB QL。
与需要 Java EE 容器的 EJB 实体 Bean 不同,JPA 可以在独立的 Java SE 应用程序中使用。这种灵活性使开发人员能够在企业应用程序和小型 Java 项目中使用 JPA,而无需应用程序服务器的额外开销。此外,JPA 提供了自动事务管理,使开发人员无需手动处理提交和回滚操作。
JPA 的另一个关键优势是其供应商独立性。API 定义了一个标准的持久化模型,但开发人员可以选择任何 JPA 提供者,例如 Hibernate、EclipseLink 或 OpenJPA。这种解耦提供了更多的灵活性,并减少了依赖特定的 ORM 实现。
尽管 Hibernate 已经得到广泛使用,JPA 的标准化为企业应用带来了统一性。许多项目继续将 Hibernate 作为 JPA 提供者使用,但现在他们可以依赖一个通用的 API,而不是被锁定在单一的 ORM 框架中。Hibernate 的许多创新最终都融入了 JPA 标准:通过代理对象实现的透明懒加载、处理实体生命周期状态(临时、持久和分离)的解决方案、用于跟踪实体变化的持久化上下文概念,以及其复杂的缓存机制。
就连 JPA 的查询语言(JPQL)也深受 Hibernate 的 HQL(Hibernate 查询语言)影响,采用了面向对象的查询方法。其他塑造了 JPA 的关键 Hibernate 特性还包括其用于管理实体关系的级联操作、用于并发控制的乐观锁策略,以及其请求会话模式,这一模式最终演变成了 JPA 的 EntityManager 概念。
随着 JPA 在 2006 年的引入,EJB 实体 Bean 迅速过时。开发者现在可以访问一个更简单、更直观的持久化模型,而无需 EJB 的重重量特性。JPA 也加速了 Java EE 5 的采用,使企业开发更加便捷。
JPA 简化了数据库访问,但管理仓库和编写查询仍然繁琐。开发者仍然需要为仓库管理编写样板代码。获取、更新和删除记录需要定义自定义查询或编写大量代码。
除此之外,到了 21 世纪头十年末,NoSQL 数据库的兴起正在重塑数据存储格局。虽然关系型数据库在几十年间一直是主流选择,但网络应用、大数据和实时处理的爆炸式增长带来了传统关系型数据库难以满足的新需求。MongoDB、Cassandra、Redis 和 Neo4j 等 NoSQL 数据库因其为特定场景提供了更好的可扩展性、灵活性和性能而广受欢迎。与强制执行严格模式的关系型数据库不同,NoSQL 数据库允许更动态的数据模型,使其成为云原生应用和分布式系统的理想选择。
2010年Spring Data诞生
认识到需要一种更简单、更统一的方式来与关系型和非关系型数据库交互,Spring Data 于 2010 年作为 Spring 生态系统的一部分被引入。其目标是为数据访问提供一致的、高级的抽象,消除重复的样板代码,并让开发者能够专注于业务逻辑而不是基础设施。Spring Data 不再需要手动定义查询或实现仓库模式,而是引入了仓库的概念,这些仓库根据方法名自动生成查询,减少了开发者需要编写的代码量。
在 Spring Data 旗下发布的第一个模块是 2011 年 4 月发布的 Spring Data Neo4j,仅仅几个月后,在 2011 年 7 月,Spring Data JPA 1.0 发布了。
虽然 JPA 已经简化了 ORM,但 Spring Data JPA 更进一步,引入了自动查询生成、分页和声明式事务管理。开发者不再需要为简单查询编写 SQL 或 JPQL——Spring Data JPA 可以从方法名中推导出查询,使数据库访问更加直观,并减少了样板代码的需求。
2011年Spring Data MongoDB诞生
2011 年 10 月,Spring Data MongoDB 1.0 发布。此时,MongoDB 已成为主流的 NoSQL 文档数据库,为开发者提供了灵活的无模式数据模型。与需要复杂迁移才能更改模式的传统关系型数据库不同,MongoDB 允许应用程序动态演进。
2012年Spring Data Redis 诞生
下一个重要里程碑出现在 2012 年 5 月,Spring Data Redis 1.0 发布。与传统数据库不同,Redis 是一个以内存优先的键值数据库,以其卓越的速度和多功能性而闻名。最初于 2009 年开发,Redis 迅速成为现代架构的关键组成部分,支持缓存层、实时分析、会话存储,甚至消息代理系统。
未来展望
在接下来的几年里,新的 Spring Data 集成不断发布,而随着多模型数据库、无服务器数据库和边缘计算的出现,该领域继续快速发展。这让我们不禁思考:当面对不断变化的数据世界时,Java 将何去何从?
未来并非在于选择 SQL 还是 NoSQL,而在于为合适的任务选择合适的数据模型。这一理念体现在像 CockroachDB 和 FaunaDB 这类现代数据库中,它们模糊了传统分类的界限,同时提供 SQL 接口和分布式 NoSQL 般的可扩展性。
Java 数据访问库的演进似乎也遵循这一趋势。Project Loom 的虚拟线程承诺将革新 Java 处理数据库连接的方式,可能使反应式编程模式在高吞吐量应用中从必要条件变为可选条件。我们可以预期 Java 平台上的数据访问将演进为在不同数据模型之间提供一致体验,同时利用 Java 的新并发特性。
人工智能和机器学习的兴起也在推动 Java 进行适应。数据领域的新宠是向量数据库。尽管向量数据库已经存在一段时间,但新获得的能力——即寻找 AI 模型为任何非结构化数据创建向量表示——提升了数据库有效处理向量和向量操作(如通过 KNN/ANN 进行语义搜索)的需求。
我们正看到 Java 应用程序对无缝交互向量数据库和大型语言模型的需求日益增长,同时保持 Java 开发人员所期望的类型安全性和可靠性。我们将看到针对这些用例的新标准出现吗?就像 JPA 标准化 ORM 一样。Java 将如何演变以应对边缘实时数据处理需求的增长?随着无服务器数据库的普及,Java 的传统连接池和事务管理模式将如何适应这些新范式?这一趋势已经在 Spring AI 等项目中有可见迹象。