Skip to content

13. SQL Server 2014

接下来我们将讨论如何将针对 MySQL 所做的修改移植到 SQL Server 2014 上。

13.1. 设置工作环境

13.1.1. Eclipse 环境

我们将使用以下 Eclipse 环境:

  

上述 SQL Server 项目位于 [<examples>/spring-database-config\sqlserver\eclipse] 文件夹中。

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

13.1.2. 生成数据库

与处理 Oracle 和 DB2 时一样,我们需要将 SQL Server JDBC 驱动程序安装到本地 Maven 仓库中。

  

[install.bat] 文件包含以下代码:

"%M2_HOME%\bin\mvn.bat" install:install-file -Dfile=sqljdbc4-3.0.jar -Dpackaging=jar -DgroupId=com.microsoft.sqlserver -DartifactId=sqljdbc4 -Dversion=4.0

其中 [%M2-HOME%] 是 Maven 安装目录(参见第 23.2 节第 466 页)。安装完成后,可在 [pom.xml] 文件中通过以下依赖项引用 SQL Server JDBC 驱动程序:


        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>sqljdbc4</artifactId>
            <version>4.0</version>
</dependency>

在本指南的其余部分中,连接到 SQL Server 数据库将使用凭据 [sa / msde]。启动 SQL Server 及其客户端 [MsManager](参见第 23.9 节)。

  • 在 [1] 中,加载 SQL 脚本 [<examples>\spring-database-config\sqlserver\databases\dbproduits.sql];
  • 在[2]中,无法在项目[spring-jdbc-01至03]中使用同一个[PRODUCTS]表。原因是:
    • 项目 [spring-jdbc-01 和 02] 在插入行时会指定主键;
    • 而 [spring-jdbc-03] 项目插入的行不带主键,并期望由数据库管理系统 (DBMS) 自动生成。要实现这一点,主键 [ID] 必须为 [Identity] 类型。然而,在 SQL Server 中,该类型仅支持自动生成主键,不允许插入带有用户定义主键的行。因此会报错,且我无法绕过此问题。 [spring-jdbc-01 和 02] 项目使用不支持自动生成主键的 [PRODUCTS] 表。而 [spring-jdbc-03] 项目则使用支持自动生成主键的 [PRODUCTS2] 表。

现在,运行这些配置:

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

它们都应该通过。

现在让我们生成 [dbproduitscategories] 数据库。对 [dbproduitscategories] 重复创建 [dbproduits] 时所用的步骤。要加载的 SQL 脚本位于 [<examples>\spring-database-config\sqlserver\databases\ dbproduitscategories.sql];

  

现在,运行以下配置:

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

两者都应通过。

13.2. 配置 JDBC 层

 

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

该项目与针对 MySQL 数据库管理系统 (DBMS) JDBC 层的 [mysql-config-jdbc] 配置项目类似(参见第 3.3 节)。此处仅列出变更内容:

[pom.xml] 文件导入了 SQL Server 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>
        <!-- dépendances variables ********************************************** -->
        <!-- driver JDBC from SGBD -->
        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>sqljdbc4</artifactId>
            <version>4.0</version>
        </dependency>
        <!-- dépendances constantes ********************************************** -->
        ...
    </dependencies>
...
</project>
  • 第 18-22 行:SQL Server JDBC 驱动程序;

第二个改动位于 [ConfigJdbc] 类中,该类定义了数据库凭据:


    // paramètres de connexion
    public final static String DRIVER_CLASSNAME = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
    public final static String URL_DBPRODUITS = "jdbc:sqlserver://localhost\\SQLEXPRESS:1433;databaseName=dbproduits";
    public final static String USER_DBPRODUITS = "sa";
    public final static String PASSWD_DBPRODUITS = "msde";
    public final static String URL_DBPRODUITSCATEGORIES = "jdbc:sqlserver://localhost\\SQLEXPRESS:1433;databaseName=dbproduitscategories";
    public final static String USER_DBPRODUITSCATEGORIES = "sa";
public final static String PASSWD_DBPRODUITSCATEGORIES = "msde";

可以进行的第三项修改是调整 [PreparedStatement] 支持的参数最大数量:


    // max number of parameters of a [PreparedStatement]
    public final static int MAX_PREPAREDSTATEMENT_PARAMETERS = 2000;

[JUnitTestPushTheLimits] 测试会为 5,000 种产品生成 SQL 语句,这将生成包含 5,000 个参数的 [PreparedStatement] 对象。MySQL 支持该数值。而 SQL Server 返回了错误,指出该限制为 2,100。

第四项更改涉及 [spring-jdbc-03] 项目所使用的表。该表不再是 [PRODUCTS],而是 [PRODUCTS2]:


    // ordres SQL [jdbc-03]
    public final static String V2_INSERT_PRODUITS = "INSERT INTO PRODUITS2(NOM, CATEGORIE, PRIX, DESCRIPTION) VALUES (?, ?, ?, ?)";
    public final static String V2_DELETE_ALLPRODUITS = "DELETE FROM PRODUITS2";
    public final static String V2_DELETE_PRODUITS = "DELETE FROM PRODUITS2 WHERE ID=?";
    public final static String V2_SELECT_ALLPRODUITS = "SELECT ID, NOM, CATEGORIE, PRIX, DESCRIPTION FROM PRODUITS2";
    public final static String V2_SELECT_PRODUIT_BYID = "SELECT NOM, CATEGORIE, PRIX, DESCRIPTION FROM PRODUITS2 WHERE ID=?";
    public final static String V2_SELECT_PRODUIT_BYNAME = "SELECT ID, CATEGORIE, PRIX, DESCRIPTION FROM PRODUITS2 WHERE NOM=?";
public final static String V2_UPDATE_PRODUITS = "UPDATE PRODUITS2 SET NOM=?, PRIX=?, CATEGORIE=?, DESCRIPTION=? WHERE ID=?";

13.3. 配置 OpenJPA JPA 层

 

[sqlserver-config-jpa-openjpa] 项目用于配置测试架构中的 [JPA] 层:

该项目类似于针对 MySQL 数据库管理系统 (DBMS) 的 OpenJpa JPA 层的 [mysql-config-jpa-openjpa] 配置项目(参见第 8.3 节)。 实际上,这两种数据库管理系统都使用 [@GeneratedValue(strategy = GenerationType.IDENTITY)] 注解来生成主键。需要进行两处修改,它们位于 [ConfigJpa] 类中 [jpaVendorAdapter] Bean 的定义中:


    // the provider JPA
    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
        OpenJpaVendorAdapter openJpaVendorAdapter = new OpenJpaVendorAdapter();
        openJpaVendorAdapter.setShowSql(false);
        openJpaVendorAdapter.setDatabase(Database.SQL_SERVER);
        openJpaVendorAdapter.setGenerateDdl(true);
        return openJpaVendorAdapter;
}
  • 第 6 行:我们告知 JPA 实现,它将与 SQL Server 数据库进行交互。随后,JPA 实现将采用该数据库管理系统(DBMS)专有的数据类型和专有 SQL 语句。

第二个改动涉及与 [PRODUCTS] 和 [PRODUCTS2] 表关联的 JPA 实体:

  

[Product] 实体与 [PRODUCTS] 表相关联,且不自动生成主键(未使用 [@GeneratedValue] 注解):


@Entity(name = "Produit1")
@Table(name = ConfigJdbc.TAB_PRODUITS)
public class Produit {
 
// fields
@Id
@Column(name = ConfigJdbc.TAB_PRODUITS_ID)
private Long id;

[Product2] 实体与 [PRODUCTS2] 表相关联,并自动生成主键:


@Entity(name = "Produit2")
@Table(name = ConfigJdbc.TAB_PRODUITS2)
public class Produit2 {
 
// fields
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = ConfigJdbc.TAB_PRODUITS_ID)
private Long id;

此外,生成 [dbproduits] 数据库的项目必须进行修改,以表明数据库中现在有两个 JPA 实体:

  

[persistence.xml] 文件的更改如下:


<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
    <persistence-unit name="generic-jpa-entities-dbproduits" transaction-type="RESOURCE_LOCAL">
        <!-- entities JPA -->
        <class>generic.jpa.entities.dbproduits.Produit</class>
        <class>generic.jpa.entities.dbproduits.Produit2</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
    </persistence-unit>
</persistence>

[generic-create-dbproduits] 项目适用于所有数据库管理系统(DBMS)。此前所考察的 JPA 层中并不包含 [Product2] 实体。因此,人们可能会质疑:对于这些数据库管理系统而言,引用一个不存在的 JPA 实体是否会导致项目失败。测试表明,情况并非如此。

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

13.4. 配置 Hibernate JPA 层

 

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

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

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

 

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

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

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