Skip to content

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高级”水平。届时,读者可借助以下著作继续深造:

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 服务;