1. 简介
本文档的 PDF 版本可在此处获取 |HERE||。
本文档的示例可通过 |HERE| 获取。
1.1. 内容
本文旨在探讨数据库的各种运行配置。考虑以下分层架构:
![]() |
执行流程从左向右:
- 首先执行的是 [ui] 层(Use Interface)中的某个类。该类将实例化 [metier] 和 [dao] 层。 如果 [ui] 层是一个图形界面,它将等待用户的操作。用户的操作可能会触发架构中所有层(直至数据库)中方法的执行。这些执行的结果将以某种形式呈现给用户;
各层的作用可能如下:
- [JDBC]层(Java DataBase Connectivity)是一个通用的数据库访问接口。它始终向[DAO]层提供相同的接口。 如果更换 SGBD,只需更换 JDBC 驱动程序即可。只要严格遵守若干规则,[DAO] 层便不会发生变化。 然而,很难确保 SGBD 之间实现 100% 的可移植性,因为这些版本通常包含大量专有 SQL 代码,而这些代码往往能带来性能提升,因此很难被忽略。 一旦使用了专有 SQL,就无法再实现与 SGBD 之间的可移植性。此外,不同 SGBD 版本通常在主密钥自动生成策略上存在差异,且保留字也各不相同。 不过,本文中我们仍成功将研究的 JDBC 架构移植到了六个不同的 SGBD 实例上,前提是每个实例都需要一个独立的配置项目;
- [DAO]层提供了一个用于访问特定数据库数据的接口(需与JDBC接口区分,后者提供适用于所有SGBD的方法);
- [métier]层实现应用程序的管理规则或业务规则。
- 其输入数据包括:通过 [dao] 层从数据库获取的数据,以及/或由 [ui] 层传递的用户数据;
- 该层生成的数据可通过 [dao] 层保存至数据库,和/或返回给发起查询的 [ui] 层,以便向用户显示;
- [ui]层是执行用户操作并向用户返回操作结果的层;
如上所述,[DAO]层向[JDBC]层发送SQL请求,以便在SGBD中执行。 自2006年以来,该架构可演变为如下形式:
![]() |
现在,由 JPA 层(Java Persistence API)向 JDBC 层发送 SQL 请求,并接收其结果。 [JPA]层向[DAO]层提供用于持久化/修改/删除/获取对象的操作。[DAO]层不再发出SQL指令。 这种方法具有更高的可移植性,因为 JPA 实现负责处理 SGBD 之间的差异,但其运行速度慢于 JDBC 技术。 我们将进行性能测试来证明这一点。JPA 技术将 Hibernate [http://hibernate.org/] 框架多年前所做的工作进行了规范化。
我们将研究两个 [DAO] 层,采用以下两种架构之一:
![]() |
![]() |
我们将要求 [DAO1] 和 [DAO2] 这两层实现相同的 [IDAO] 接口。因此,针对这两种配置的 [JUnitTestsDao] 测试将保持一致,从而使我们能够比较其性能。 [DAO1]层将使用Spring JDBC实现,而[DAO2]层将使用Spring JPA实现;
完成上述操作后,我们将按以下方式在 Web 上暴露 [IDAO] 接口:
![]() |
- 在 [1] 中,[IDAO] 层通过由 Spring MVC 实现的 [2] Web 层在 Web 上进行暴露。 确实是接口 [IDAO] 被公开,我们将根据该接口采用 [DAO-JDBC] 或 [DAO-JPA-JDBC] 架构进行实现,构建两个版本的 Web 服务;
- 在 [B] 架构中,远程客户端使用 Web 服务暴露的 URL 接口,从而访问 [IDAO-serveur] 层的方法。 我们将确保 [DAO-Client] 和 [3] 层实现 [IDAO-serveur] 和 [1] 接口。 这样,我们就可以使用已经使用过两次的同一测试 [JUnitTestsDao] [4];
- 在 [3] 中,[DAO-client] 层将通过 Spring 实现 RestTemplate;
完成上述操作后,我们将对Web服务访问进行安全加固:
![]() |
- 在 [5] 中,客户端的 HTTP 请求将通过一个使用 Spring Security 实现的身份验证层;
完成上述操作后,我们将把之前的架构演进为以下架构:
![]() |
- 在 [3] 中,客户端应用程序本身即为一个 Web 应用程序。该应用程序将提供一个表单 [5],用于查询安全 Web 服务的 URL。 对安全 Web 服务的 HTTP 访问将通过一个用 JavaScript 实现的 [DAO-client-js] 层进行。该架构实现了所谓的跨域请求:
- [2] Web 服务返回 URL 格式的 [http://machine1:port1/];
- 客户端Web应用程序[3]是从URL和[http://machine2:port2/]下载的。 如果 [http://machine2:port2/] 与 [http://machine1:port1/] 不完全一致(同一台机器、同一端口),则客户端浏览器将阻止 HTTP 层发出的 [DAO-client-js] 调用。 为解决此问题,Web 服务必须允许跨域请求。我们将探讨具体实现方法;
本文介绍的项目已在以下六个 SGBD 版本上经过测试:
- MySQL 5 Community Edition;
- SQL Server 2014 Express;
- PostgreSQL 9.4;
- Oracle Express 11g 版本 2;
- IBM DB2 Express-C 10.5;
- Firebird 2.5.4;
针对上述每个 SGBD,我们开发了四种不同的 [DAO] 层:
- 一个基于 Spring 实现的层 JDBC;
- 一个基于 Spring JPA 并使用 Hibernate 提供程序 JPA 实现的层;
- 一个基于 Spring JPA 并使用 JPA EclipseLink 提供程序实现的层;
- 一个基于 Spring 实现的层 JPA 及其提供者 JPA OpenJPA;
因此,这里展示了一组共二十四种不同的配置。我们进行了大量的代码重构:
- 大部分代码仅编写一次。它基于两个Maven配置项目:
- 一个用于配置 JDBC 层;
- 另一个负责配置 JPA 层;
![]() |
![]() |
针对特定 SGBD 的 JDBC [1] 配置层 Maven 项目包含两点:
- 导入驱动程序存档 JDBC;
- 定义所用数据库的访问凭据,以及 [DAO1] 层将向 JDBC 驱动程序发送的各种 SQL 命令。 尽管 SQL 已标准化,但我们仍遇到了可移植性问题,这主要是因为查询中包含的表名/列名在某些 SGBD 中被证明是禁止使用的关键字 (例如 ROLES 表对应 DB2,PASSWORD 列对应 Firebird)。 此外,尽管列名通常不区分大小写,但在处理PostgreSQL时,其主键表中的ID列却出现了问题。 它要求该列名称必须为全小写的 id。这正是典型的意外可移植性问题;
针对特定 SGBD 的 JPA 和 [2] 配置层面的三个 Maven 项目,其配置也包含两点:
- 导入 JPA 实现的归档文件;
- 配置用于连接特定 SGBD 的 JPA 实现。 实际上,正是 JPA 层向 JDBC 层发送 SQL 指令。 为了有效运作,它必须知道 SGBD,以便向其发送 SQL 命令,而该层会识别这些命令。 这些命令可利用作为该 SGBD 所有者的 SQL,以及后者的特定特性(数据类型、序列、触发器、存储过程、主键自动生成等);
因此,共有二十四个 Maven 配置项目(4 种配置 × 6 个 SGBD),所有其他数据库操作项目都将基于这些配置项目。 在上图所示的架构中,由于 [DAO1] 和 [DAO2] 层提供相同的接口,因此上述两个架构的 24 个配置将使用单一的测试类 [JUnitTestsDao] 进行测试。 一旦验证了这些架构,就不再有困难:
- 将数据库发布到 Web 的 Maven 项目基于这两种架构。因此,这里同样有 24 种可能的配置;
- 用于保障Web服务访问安全的Maven项目基于前一个项目,同样有24种可能的配置;
- 最后,支持向安全Web服务发起跨域请求的Maven项目基于前一个项目,同样有24种可能的配置;
本研究基于 SGBD、MySQL5 以及 JPA Hibernate 实现进行。 随后将代码移植到 JPA Eclipselink 和 OpenJPA 实现中。 最后,我们将代码移植到其他数据库(PostgresQL,Oracle;SQL,Server;DB2,Firebird)。
本课程面向初学者。其中涉及的大部分概念都会进行讲解。无需具备数据库编程或Web编程知识。但需要扎实掌握SQL语言,因为所使用的SQL查询语句不会进行详细说明。
要理解示例,需要具备Java语言的基础知识,这些知识在任何Java入门课程中都能学到。 文档[《Java语言入门》(1998)]的前两章即可满足需求。虽然这是一份旧文档(1998年出版,2002年修订),但基础内容依然完整。若需系统学习,可参阅Jean-Marie Doudoux所著的巨著[http://www.jmdoudoux.fr/java]。
本文绝非详尽无遗,仅旨在提供一种方法论及可在类似场景中复用的代码。本文的撰写方式使得读者无需手边有电脑即可阅读,因此提供了大量屏幕截图。
尽管本文档并未涵盖Java语言的所有功能及其所有应用领域,但仍可作为Java语言的学习资料。初学者若能系统地研读本文档(即使未完全通读),在语言运用及Spring框架应用方面都将达到“Java高级”水平。届时,读者可借助以下著作继续深造:
- [通过实例学习 Spring MVC 和 Thymeleaf(2015)],该书通过介绍“Web编程”分支(MVC)来深化对Spring生态系统的学习;
- [客户端/服务器示例 - AngularJS 1.x / Spring 4 (2014)],该书介绍了客户端/服务器Web架构,其中客户端采用[AngularJS]框架实现,服务器则采用[Spring MVC]框架;
- [使用 NetBeans IDE 和 GlassFish 应用服务器入门 Java EE (2012)] 脱离了 Spring 生态,转而采用基于 JSF(Java Server Faces)和 EJB(Enterprise Java Bean)的 Web 架构;
- [使用 Android Studio 进行 Android 平板电脑编程入门(2016)] [http://tahe.developpez.com/android/exemples-intellij-aa],描述了一种客户端/服务器架构,其中客户端为 Android 平板电脑,服务器为由 Spring 实现的 Web 服务 MVC;
1.2. 来源
本文档有两个主要来源:
- [ref1] :[Spring MVC et Thymeleaf par l'exemple] 至 URL [通过实例学习 Spring MVC 和 Thymeleaf(2015)]。 本文档基于另一套数据库,延续了 [ref1] 中完成并展示的工作。简而言之,它脱离了 MVC 中基于 Spring 的 Web 编程环境。 之所以决定将其单独成文,是因为我发现[ref1]中用于在Web上展示数据库的代码和方法具有复用价值;
- [ref2] :[Persistance Java par la pratique] 至 URL [Java 5 持久化实践指南 (2007)];
若想深入了解Spring,可参考以下资料:
- Spring 框架的参考文档 [http://docs.spring.io/spring/docs/current/spring-framework-reference/pdf/spring-framework-reference.pdf];
- 在URL和[http://spring.io/guides]上可以找到许多Spring教程;
- 专门介绍 Spring 的网站 [developpez.com];
- 教程 [http://www.tutorialspoint.com/spring/spring_tutorial.pdf];
对于SQL知识储备不足的读者,可通过[Introduction au langage SQL avec le SGBD Firebird]一书在URL [Firebird 数据库管理系统中的 SQL 语言入门 (2006)]处掌握基础知识。
1.3. 使用的工具
以下示例已在以下环境中经过测试:
- Windows 8.1 Pro 64位系统;
- JDK 1.8(第23.1节);
- IDE Spring Tool Suite 3.6.3(第1节);
- Chrome 浏览器(未使用其他浏览器);
- Chrome 扩展程序 [Advanced Rest Client](第 1 段);
- SGBD MySQL 5.6 社区版(第 23.4 段);
- SGBD SQL Server 2014 Express(第23.9段);
- SGBD PostgreSQL 9.4(第 23.7 节);
- SGBD Oracle Express 11g 版本 2(第 23.6 节);
- SGBD IBM DB2 Express-C 10.5(第 23.8 节);
- SGBD Firebird 2.5.4(第 23.10 节);
- 其六个 SGBD 客户端的 EMS 管理器(第 23.5 段);
请注意 JDK 1.8。案例研究中的一种方法使用了 Java 8 的 [java.lang] 包中的方法。
大多数示例都是 Maven 项目,可通过 Eclipse、NetBeans 或 IDE 任意打开。下文中的屏幕截图均来自 Spring Tool Suite(Eclipse 的一个变体)。
1.4. 示例
示例以可下载文件的形式提供,可在 URL [http://tahe.developpez.com/java/spring-database] 处获取。
![]() |
- [1] 文件中包含示例文件夹;
- 转换为 [2],文件夹 [spring-core] 包含 Spring 学习项目;
- 在 [3] 中,[spring-database-config] 文件夹包含六个数据库的配置项目 JDBC 和 JPA;
![]() |
- 在 [4] 中,包含 SGBD 的 Oracle 配置。其中包含三个文件夹:
- [databases] 包含用于生成文档所用两个数据库的脚本 SQL;
- [jdbc-driver] 包含 Oracle 驱动程序 JDBC 及其安装脚本,用于将其安装到本地 Maven 仓库中;
- [eclipse] 包含 [5] 以及四个 Oracle 配置项目:
- [oracle-config-jdbc] 配置用于访问 SGBD 的 JDBC 层;
- [oracle-config-jpa-hibernate] 配置了通过 JPA 访问 SGBD 的层,并使用 JPA Hibernate 提供程序;
- [oracle-config-jpa-eclipselink] 配置 JPA 访问层,用于访问 SGBD,并使用 JPA Eclipselink 提供程序;
- [oracle-config-jpa-openjpa] 使用提供程序 JPA OpenJPA 配置 JPA 访问 SGBD 的层;
- 在 [6] 中,文件 [eclipse config / launch configurations] 包含运行配置,用户可将其导入 Eclipse,随后根据自身环境进行调整;
![]() |
- 在 [7] 中, 文件夹 [spring-database-generic] 包含所有用于访问 SGBD 的代码,该代码同时适用于六个 SGBD 和三个供应商 JPA;
- 在 [8] 中,[spring-jdbc] 包含四个项目,其中包含 API、JDBC 以及 Spring JDBC;
- 在 [9] 中,[spring-jpa / spring-jpa-generic] 是利用 JPA 层访问数据库的项目。 [generic-create-db*] 项目是 JPA 项目,用于创建由 JPA 层使用的数据库;
![]() |
-
在 [10] 中,[spring-webjson] 文件夹包含将数据库发布到 Web 上的项目;
- [spring-webjson-server-jdbc-generic] 是通过 Spring JDBC 访问的数据库的 Web 服务;
- [spring-webjson-server-jpa-generic] 是通过 Spring JPA 访问数据库的 Web 服务;
- [spring-webjson-client-generic] 是唯一一个可访问上述两个 Web 服务的客户端;
-
在 [11] 中,[spring-security] 文件夹包含通过安全访问方式在 Web 上暴露数据库的项目;
- [spring-security-server-jdbc-generic] 是安全 Web 服务,用于公开通过 Spring JDBC 访问的数据库;
- [spring-security-server-jpa-generic] 是通过 Spring JPA 访问的数据库的安全 Web 服务;
- [spring-security-client-generic] 是唯一一个可访问上述两个安全 Web 服务的客户端;
-
在 [12] 中,[spring-cors] 文件夹包含通过安全访问方式在 Web 上公开数据库的项目,这些项目支持跨域访问,例如来自浏览器 JavaScript 代码的访问;
- [spring-cors-server-jdbc-generic] 是一个支持跨域访问的安全 Web 服务,该服务公开了通过 Spring JDBC 访问的数据库;
- [spring-cors-server-jpa-generic] 是一个支持跨域访问的安全 Web 服务,该服务公开了通过 Spring JPA 访问的数据库;
- [spring-cors-client-generic] 是一个 Web 应用程序,用于查询前两个 Web 服务;












