Skip to content

10. Oracle Express 11g Release 2

接下来,我们将探讨如何将 MySQL5 所完成的工作移植到 Oracle Express 11g release 2 上。

10.1. 工作环境的搭建

10.1.1. Eclipse 环境

我们将使用以下 Eclipse 环境:

  

上述 Oracle 项目位于 [<exemples>/spring-database-config\oracle\eclipse] 文件夹中。

注意:执行 [Alt-F5] 可重新生成所有 Maven 项目。

启动 Oracle Express 及其客户端 [OraManager](参见第 23.6 节)。我们将生成:

  • 使用项目 [generic-create-dbproduits] 生成数据库 [dbproduits];
  • 使用项目 [generic-create-dbproduitscategories] 生成数据库 [dbproduitscategories];

10.1.2. 创建用户

现在所有操作都在 [OraManager] 中进行。必须启动 Oracle 进程 SGBD。系统管理员使用 system / system 凭据(需预先配置)。我们将创建两个用户:

  • [DBPRODUITS / dbproduits],该用户将拥有数据库 [dbproduits];
  • [DBPRODUITSCATEGORIES / dbproduitscategories],该用户将拥有数据库 [dbproduits];
  • 在 [6-7] 中,标识符为 [system / system];
  • 在 [14] 中:改为 dbproduits
  • 在 [16] 中,用户已创建但无足够权限登录。我们将通过脚本为其授予权限:SQL [17-18];
  • 在 [19] 中,将用户名改为大写;

我们重复上述步骤来创建用户 [DBPRODUITSCATEGORIES / dbproduitscategories]:

  

10.1.3. 将 Oracle 的 JDBC 驱动程序安装到 Maven 仓库

Oracle 的 JDBC 驱动程序在中央 Maven 仓库中不可用。必须从 Oracle 下载 [http://www.oracle.com/technetwork/apps-tech/jdbc-112010-090769.html]:

下载完成后,需将其安装到本地 Maven 仓库中。可通过以下脚本完成:

"%M2_HOME%\bin\mvn.bat" install:install-file -Dfile=ojdbc6.jar -Dpackaging=jar -DgroupId=com.oracle.jdbc -DartifactId=ojdbc6 -Dversion=1.0

其中需将 [%M2_HOME%] 替换为 Maven 的安装目录路径(参见第 23.2 节)。完成此操作后,即可通过以下配置将 JDBC 驱动程序导入 Maven 项目:


        <dependency>
            <groupId>com.oracle.jdbc</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>1.0</version>
</dependency>

10.1.4. 生成 [dbproduits] 数据库

现在我们已拥有用户 [DBPRODUITS / dbproduits],将使用以下凭据连接到 Oracle:

  • 在 [6] 中,改为 dbproduits
  • 在 [9] 中,我们将使用 [DBPRODUITS] 作为基础;

在项目 [oracle-config-jdbc] 的类 [ConfigJdbc] 中,使用的连接参数如下:


    public final static String DRIVER_CLASSNAME = "oracle.jdbc.OracleDriver";
    public final static String URL_DBPRODUITS = "jdbc:oracle:thin:@localhost:1521:xe";
    public final static String USER_DBPRODUITS = "DBPRODUITS";
    public final static String PASSWD_DBPRODUITS = "dbproduits";
    public final static String URL_DBPRODUITSCATEGORIES = "jdbc:oracle:thin:@localhost:1521:xe";
    public final static String USER_DBPRODUITSCATEGORIES = "DBPRODUITSCATEGORIES";
public final static String PASSWD_DBPRODUITSCATEGORIES = "dbproduitscategories";

您需要根据您的 Oracle 配置进行调整。

在项目 [oracle-config-jpa-eclipselink] 中,实体 JPA 的定义如下:

  

package generic.jpa.entities.dbproduits;

import generic.jdbc.config.ConfigJdbc;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

@Entity(name="Produit1")
@Table(name = ConfigJdbc.TAB_PRODUITS)
public class Produit {

    // 字段
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="genSeqProduits")
  @SequenceGenerator(name="genSeqProduits",sequenceName="PRODUITS_SEQUENCE", allocationSize=5)
    @Column(name = ConfigJdbc.TAB_PRODUITS_ID)
    private Long id;
    @Column(name = ConfigJdbc.TAB_PRODUITS_NOM, unique = true, length = 30, nullable = false)
    private String nom;
    @Column(name = ConfigJdbc.TAB_PRODUITS_CATEGORIE, nullable = false)
    private int categorie;
    @Column(name = ConfigJdbc.TAB_PRODUITS_PRIX, nullable = false)
    private double prix;
    @Column(name = ConfigJdbc.TAB_PRODUITS_DESCRIPTION, length = 100, nullable = false)
    private String description;

...
}
  • 第 18-19 行:表 [PRODUITS] 的主键生成策略为 [strategy=GenerationType.SEQUENCE]。 对于 MySQL,此前使用的是策略 [@GeneratedValue(strategy = GenerationType.IDENTITY)]。在 Oracle Express 11g 中,该策略不可用;
  • 第 18 行:指定主键将通过通常称为序列的数字生成器生成;
  • 第 19 行:序列生成器(属性 name 引用第 18 行的生成器)将在数据库 [dbproduits] 中创建一个名为 [PRODUITS_SEQUENCE] 的序列。 由于需要确保 JPA 各实现之间的可移植性,因此为序列命名至关重要。 否则,若缺少第19行,三个JPA实现将创建名称不一致的序列,导致JPA2无法利用JPA1创建的数据库;

现在我们可以执行 [generic-create-dbproduits-eclipselink] 配置了:

执行此配置将创建两个对象:

  • 一个表 [PRODUITS];
  • 一个名为 [PRODUITS_SEQUENCE] 的序列

表 [PRODUITS] 中的 DDL 如下:

 

主键 [ID] 并非像 MySQL 那样采用自增机制。 然而,项目 [spring-jdbc-03] 假设 SGBD 负责生成表 [PRODUITS] 的主键。 我们将创建一个 triggerdéclencheur。触发器是 SGBD 中的一个存储过程,会在特定条件下执行。 我们将创建一个触发器,该触发器在每次插入新数据时,会根据配置 JPA 创建的序列 [PRODUITS_SEQUENCE],生成所插入产品的主键。

  • 在 [6] 中,每次插入前都会执行触发器 [PRODUITS_ID_TRIGGER] [4];
  • 在 [7] 中,一个专属于 SGBD 的 Oracle 存储过程。 该存储过程指定,即将插入的行中的字段 [ID] 必须使用名为 [PRODUITS_SEQUENCE] 的生成器生成的以下值进行初始化;
 

数据库 [dbproduits] 现已准备就绪。请执行以下配置:

  • [spring-jdbc-generic-01.IntroJdbc01];
  • [spring-jdbc-generic-01.IntroJdbc02];
  • [spring-jdbc-generic-03.JUnitTestDao1] ;
  • [spring-jdbc-generic-03.JUnitTestDao2] ;

所有配置都必须成功。

10.1.5. 生成数据库 [dbproduitscategories]

  

现在我们执行项目 [generic-create-dbproduitscategories],该项目将生成数据库 [dbproduitscategories]。 在此之前,在 [OraManager] 中,我们将使用 [DBPRODUITSCATEGORIES / dbproduitscategories] 的凭据登录,以便观察对 [dbproduitscategories] 数据库所做的修改:

  

所使用的 JPA 实体具有以下主键生成策略:

[Categorie]


public class Categorie implements AbstractCoreEntity {

    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="genSeqCategories")
  @SequenceGenerator(name="genSeqCategories",sequenceName="CATEGORIES_SEQUENCE", allocationSize=5)
    @Column(name = ConfigJdbc.TAB_JPA_ID)
    protected Long id;

[Produit]


public class Produit implements AbstractCoreEntity {
    // 属性
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="genSeqProduits2")
  @SequenceGenerator(name="genSeqProduits2",sequenceName="PRODUITS_SEQUENCE", allocationSize=5)
    @Column(name = ConfigJdbc.TAB_JPA_ID)
    protected Long id;

[Role]


public class Role implements AbstractCoreEntity {
    // 属性
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="genSeqRoles")
  @SequenceGenerator(name="genSeqRoles",sequenceName="ROLES_SEQUENCE", allocationSize=5)
    @Column(name = ConfigJdbc.TAB_JPA_ID)
    protected Long id;

[User]


public class User implements AbstractCoreEntity {
    // 属性
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="genSeqUsers")
  @SequenceGenerator(name="genSeqUsers",sequenceName="USERS_SEQUENCE", allocationSize=5)
    @Column(name = ConfigJdbc.TAB_JPA_ID)
    protected Long id;

[UserRole]


public class UserRole implements AbstractCoreEntity {
    // 属性
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE,generator="genSeqUsersRoles")
  @SequenceGenerator(name="genSeqUsersRoles",sequenceName="USERS_ROLES_SEQUENCE", allocationSize=5)
    @Column(name = ConfigJdbc.TAB_JPA_ID)
    protected Long id;

与[dbproduits]数据库的操作方式相同,将生成五个序列。这些序列由JPA的实现用于生成主键。 JPA 实现方案不使用触发器(如我们之前所做),而是查询序列以获取下一个主键。而我们将同样使用触发器来生成主键。这些触发器对于 [spring-jdbc-04] 项目是必需的。

我们执行配置 [generic-create-dbproduitscategories-eclipselink]:

并得到以下结果:

  

随后,我们生成五个触发器以生成这五个表的主键:

 

触发器与表的关联方式如下:

Table
Trigger
Séquence
CATEGORIES
CATEGORIES_ID_TRIGGER
CATEGORIES_SEQUENCE
PRODUITS
PRODUITS_ID_TRIGGER
PRODUITS_SEQUENCE
ROLES
ROLES_ID_TRIGGER
ROLES_SEQUENCE
USERS
USERS_ID_TRIGGER
USERS_SEQUENCE
USERS_ROLES
USERS_ROLES_ID_TRIGGER
USERS_ROLES_SEQUENCE
  

项目 [spring-jdbc-04] 要求在每个表中,列 [VERSIONING] 都必须具有默认值:

对这五个表都进行此操作。

现在,执行以下配置:

  • [spring-jdbc-generic-04.JUnitTestDao] ;
  • [spring-jpa-generic-JUnitTestDao-hibernate-eclipselink] ;

这两项配置都应成功。

10.2. 配置 JDBC 层

 

项目 [oracle-config-jdbc] 配置了以下测试架构中的 [JDBC] 层:

该项目与 SGBD 中的 JDBC 层的配置项目 [mysql-config-jdbc] 类似(参见第 3.3 节)。此处仅列出修改内容:

文件 [pom.xml] 导入了 Oracle 的驱动程序 JDBC:


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>dvp.spring.database</groupId>
    <artifactId>generic-config-jdbc</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>configuration generic jdbc</name>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.3.RELEASE</version>
    </parent>

    <dependencies>
        <!-- 变量依赖关系 ********************************************** -->
        <!-- SGBD 的驱动程序 JDBC -->
        <dependency>
            <groupId>com.oracle.jdbc</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>1.0</version>
        </dependency>
        <!-- 常量依赖项 ********************************************** -->
        ....
    </dependencies>
...
</project>
  • 第18-22行:Oracle的驱动程序JDBC替换了MySQL;

第二个修改位于定义数据库访问凭据的 [ConfigJdbc] 类中:


    // 连接参数
    public final static String DRIVER_CLASSNAME = "oracle.jdbc.OracleDriver";
    public final static String URL_DBPRODUITS = "jdbc:oracle:thin:@localhost:1521:xe";
    public final static String USER_DBPRODUITS = "DBPRODUITS";
    public final static String PASSWD_DBPRODUITS = "dbproduits";
    public final static String URL_DBPRODUITSCATEGORIES = "jdbc:oracle:thin:@localhost:1521:xe";
    public final static String USER_DBPRODUITSCATEGORIES = "DBPRODUITSCATEGORIES";
public final static String PASSWD_DBPRODUITSCATEGORIES = "dbproduitscategories";

第三项修改涉及一个 所能支持的参数最大数量:


    // [PreparedStatement] 的最大参数数
    public final static int MAX_PREPAREDSTATEMENT_PARAMETERS = 1000;

测试程序 [JUnitTestPushTheLimits] 针对 5000 种产品生成 SQL 订单,这些订单将生成包含 5000 个参数的 [PreparedStatement]。虽然 MySQL 支持该参数数量,但 Oracle 无法处理。 我们将该值降至 1000 后,问题得以解决。

 

:执行 [Alt-F5] 以重新生成所有 Maven 项目。

项目 [oracle-config-jpa-eclipseLink] 配置了测试架构中的 [JPA] 层:

该项目与 SGBD 和 MySQL 中的 JPA Eclipselink 层的配置项目 [mysql-config-jpa-eclipselink](参见第 7.3 节)类似。 此处仅列出修改内容:

第一处修改位于 [ConfigJpa] 类中,具体在 [jpaVendorAdapter] Bean 的定义部分:


    // 提供程序 JPA
    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        // 注意:JPA 实体和 Eclipselink 配置位于文件 META-INF/persistence.xml 中
        EclipseLinkJpaVendorAdapter eclipseLinkJpaVendorAdapter = new EclipseLinkJpaVendorAdapter();
        eclipseLinkJpaVendorAdapter.setShowSql(false);
        eclipseLinkJpaVendorAdapter.setDatabase(Database.ORACLE);
        eclipseLinkJpaVendorAdapter.setGenerateDdl(true);
        return eclipseLinkJpaVendorAdapter;
}
  • 第 7 行:指示实现类 JPA 将与 Oracle 数据库配合使用。实现类 JPA 随后将采用 Oracle 的专有数据类型以及 SQL。

第二项修改涉及主键生成策略。新策略已在第 10.1 节中介绍。

10.4. Hibernate 层的配置

 

:执行 [Alt-F5] 以重新生成所有 Maven 项目。

项目 [oracle-config-jpa-hibernate] 与项目 [mysql-config-jpa-hibernate](第 6.3 节)类似,采用了与将 [mysql-config-jpa-eclipselink] 移植到项目 [oracle-config-jpa-eclipselink] 时相同的修改 (第 10.3 节)。

完成这些修改后,[spring-jpa-generic-JUnitTestDao-hibernate-eclipselink]配置的执行应能成功。

10.5. JPA 层的配置 OpenJpa

 

:执行 [Alt-F5] 以重新生成所有 Maven 项目。

项目 [oracle-config-jpa-openjpa] 与项目 [mysql-config-jpa-openjpa](第 8.3 节)类似,采用了与将 [mysql-config-jpa-eclipselink] 移植到项目 [oracle-config-jpa-eclipselink] 时相同的修改 (第 10.3 节)所采用的修改。

完成这些修改后,[spring-jpa-generic-JUnitTestDao-openjpa]的配置执行应能成功。