原文:Accessing Relational Data using JDBC with Spring,译者:麻酱,校对:李强

本指南将引导你使用Spring访问关系型数据库。

你将构建什么应用

你会通过SpringJdbcTemplate搭建一个应用来访问关系型数据库。

你需要准备什么?

你如何完成这个入门指南

像其他Spring入门指南一样,你可以从头开始逐步完成每一步,也可以跳过一些你熟悉的步骤。不管怎样,最后你都将得到一份可执行的代码。

从零开始,可以点击怎样使用 Gradle 构建项目.

跳过基础步骤,请继续往下看

  • 下载并解压这个引导。或者直接使用 Git:git clone:git clone https://github.com/spring-guides/gs-relational-data-access.git
  • 进入gs-relational-data-access/initial目录
  • 跳到创建Customer对象.

完成上述步骤,你可以查看结果,并与gs-relational-data-access/complete对比。

使用Gradle构建

首先你需要编写基础构建脚本。在构建 Spring 应用的时候,你可以使用任何你喜欢的系统来构建, 如果你想使用Gradle 或者 Maven 构建那么请阅读如下代码。如果你对两者都不熟悉,可以先参考使用Gradle构建Java项目 或者 使用Maven构建Java项目

创建目录结构

在你选择的项目目录下,创建以下子目录;例如, 在Linux/Unix系统中使用如下命令: mkdir -p src/main/java/hello

└── src
    └── main
        └── java
            └── hello

创建一个Gradle文件

如下是一个 Gradle初始化文件.

build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.8.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'

jar {
    baseName = 'gs-relational-data-access'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile("org.springframework.boot:spring-boot-starter")
    compile("org.springframework:spring-jdbc")
    compile("com.h2database:h2")
    testCompile("junit:junit")
}

Spring Boot gradle 插件 提供了很多便捷的特性:

  • 它收集classpath上的所有jar包,并构建一个可运行的jar包,这样可以更方便地执行和传递你的应用。
  • 它寻找public static void main() 方法并将该类作为可执行类。
  • 它提供了一个内置的依赖解析器,使得项目可以自动匹配Spring Boot的依赖版本。当然你可以修改成任意的版本,它只是默认设置为Boot所选择的一组版本。

使用Maven构建

首先你需要编写基础构建脚本。在使用Spring构建应用程序时,你可以使用任何构建系统。如果你想使用Maven构建那么请阅读如下代码。如果你不熟悉Maven,请参阅使用Maven构建Java项目

创建目录结构

在你选择的项目目录中,创建以下子目录结构;例如, 在Linux/Unix系统中使用如下命令: mkdir -p src/main/java/hello

└── src
    └── main
        └── java
            └── hello

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>org.springframework</groupId>
    <artifactId>gs-relational-data-access</artifactId>
    <version>0.1.0</version>

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

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Spring Boot Maven 插件 提供了很多便捷的特性:

  • 它收集classpath上的所有jar包,并构建一个可运行的jar包,这样可以更方便地执行和传递你的应用。
  • 它寻找public static void main() 方法并将该类作为可执行类。
  • 它提供了一个内置的依赖解析器,使得项目可以自动匹配Spring Boot的依赖版本。当然你可以修改成任意的版本,它只是默认设置为Boot所选择的一组版本。

使用你的IDE构建

创建一个Customer类

下面是一个简单访问数据库的逻辑,我们需要创建Customer类然后实现对fisrtNamelastName属性的操作。

src/main/java/hello/Customer.java

package hello;

public class Customer {
    private long id;
    private String firstName, lastName;

    public Customer(long id, String firstName, String lastName) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return String.format(
                "Customer[id=%d, firstName='%s', lastName='%s']",
                id, firstName, lastName);
    }

    // getters & setters omitted for brevity
}

存储和读取数据

Spring 提供了一个叫做 JdbcTemplate 的类,可以简单的使用运行 sql 语句的关系型数据库和 jdbc.大多数 JDBC 的代码都需要获取资源,管理连接和异常处理,还有错误类型检查这些不相关的事,然儿 JdbcTemplate 可以让你更专注于做你想做的事情。

src/main/java/hello/Application.java

package hello;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@SpringBootApplication
public class Application implements CommandLineRunner {

    private static final Logger log = LoggerFactory.getLogger(Application.class);

    public static void main(String args[]) {
        SpringApplication.run(Application.class, args);
    }

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Override
    public void run(String... strings) throws Exception {

        log.info("Creating tables");

        jdbcTemplate.execute("DROP TABLE customers IF EXISTS");
        jdbcTemplate.execute("CREATE TABLE customers(" +
                "id SERIAL, first_name VARCHAR(255), last_name VARCHAR(255))");

        // Split up the array of whole names into an array of first/last names
        List<Object[]> splitUpNames = Arrays.asList("John Woo", "Jeff Dean", "Josh Bloch", "Josh Long").stream()
                .map(name -> name.split(" "))
                .collect(Collectors.toList());

        // Use a Java 8 stream to print out each tuple of the list
        splitUpNames.forEach(name -> log.info(String.format("Inserting customer record for %s %s", name[0], name[1])));

        // Uses JdbcTemplate's batchUpdate operation to bulk load data
        jdbcTemplate.batchUpdate("INSERT INTO customers(first_name, last_name) VALUES (?,?)", splitUpNames);

        log.info("Querying for customer records where first_name = 'Josh':");
        jdbcTemplate.query(
                "SELECT id, first_name, last_name FROM customers WHERE first_name = ?", new Object[] { "Josh" },
                (rs, rowNum) -> new Customer(rs.getLong("id"), rs.getString("first_name"), rs.getString("last_name"))
        ).forEach(customer -> log.info(customer.toString()));
    }
}

@SpringBootApplication作为一个方便使用的注解,提供了如下的功能:

  • @Configuration表明使用该注解的类是应用程序上下文(Applicaiton Context)中Bean定义的来源。
  • @EnableAutoConfiguration注解根据classpath的配置、其他bean的定义或者不同的属性设置(property settings)等条件,使Spring Boot自动加入所需的bean。
  • @ComponentScan注解使Spring在hello包(package)中搜索其他的组件、配置(configurations)和服务(service),在本例中,spring会搜索到控制器(controllers)。

main()方法使用Spring Boot的SpringApplication.run()方法来加载应用。你有没有注意到本例子中一行XML代码都没有吗?也没有web.xml文件。此web应用100%使纯java代码,因此不需花精力处理任何像基础设施或者下水管道一般的配置工作。

Spring Boot同样支持关系型内存数据库H2,并且可以自动获取Connection。因为我们使用的是spring-jdbc它可以自动帮我们创建JdbcTemplate。然后使用@Autowired JdbcTemplate注解就可以加载和使用了。

我们这个Application实现了CommandLineRunner接口,这样在程序上下文加载完成的时候我们就可以执行其run()方法来运行程序。

那么首先让我们运行JdbcTemplateexecute方法生成DDL。
其次,获取字符串列表并使用Java 8流,将它们拆分为Java数组中的firstName/lastName对。
接着使用JdbcTemplatebatchUpdate方法把解析好的数据插入到表中。batchUpdate的第一个参数是sql语句,第二个参数是一个对象数组,它循环的把对应的值放到sql的占位符?里面。

插入一条数据的使用使用JdbcTemplateinsert方法,如果是多条建议使用batchUpdate方法。

通过?占位符绑定变量的方式来避免SQL注入的攻击。

最后,您使用查询方法来搜索您的表以查找符合条件的记录。 再次使用?参数为查询创建参数,在进行调用时传入实际值。最后一个参数是用于将每个结果行转换为新的 Customer 对象的 Java 8 lambda 表达式。

Java 8 lambdas很好地映射到单个方法接口上,比如SpringRowMapper。 如果您使用的是Java 7或更早版本,则可以轻松插入匿名接口实现,并具有与 lambda 表达式正文包含的方法体相同的方法体,Spring 一样可以解析。

构建可执行的JAR

您可以使用 GradleMaven 从命令行运行应用程序。 或者,您可以构建一个包含所有必需的依赖项,类和资源的可执行 JAR 文件,然后运行该文件。 这使得在整个开发生命周期内跨越不同的环境,将服务作为应用程序发布,版本化和部署变得非常容易。 如果你使用的是Gradle,则可以使用./gradlew bootRun运行应用程序。或者你可以使用`./gradlew build构建来构建JAR文件。然后可以运行JAR文件:

java -jar build/libs/gs-relational-data-access-0.1.0.jar

如果使用Maven,可以使用./mvnw spring-boot:run运行应用程序,或者你可以使用./mvnw clean package来构建JAR文件,然后可以运行JAR文件

java -jar target/gs-relational-data-access-0.1.0.jar

上面的过程将创建一个可运行的jar,你也可以选择构建一个典型的war文件。

下面是运行的输出结果

2015-06-19 10:58:31.152  INFO 67731 --- [           main] hello.Application                        : Creating tables
2015-06-19 10:58:31.219  INFO 67731 --- [           main] hello.Application                        : Inserting customer record for John Woo
2015-06-19 10:58:31.220  INFO 67731 --- [           main] hello.Application                        : Inserting customer record for Jeff Dean
2015-06-19 10:58:31.220  INFO 67731 --- [           main] hello.Application                        : Inserting customer record for Josh Bloch
2015-06-19 10:58:31.220  INFO 67731 --- [           main] hello.Application                        : Inserting customer record for Josh Long
2015-06-19 10:58:31.230  INFO 67731 --- [           main] hello.Application                        : Querying for customer records where first_name = 'Josh':
2015-06-19 10:58:31.242  INFO 67731 --- [           main] hello.Application                        : Customer[id=3, firstName='Josh', lastName='Bloch']
2015-06-19 10:58:31.242  INFO 67731 --- [           main] hello.Application                        : Customer[id=4, firstName='Josh', lastName='Long']
2015-06-19 10:58:31.244  INFO 67731 --- [           main] hello.Application  

总结

恭喜!你已经使用Spring成功构建了一个JDBC程序。

了解更多

以下指南也可能有帮助:

想写一个新的指南或贡献一个现有的?查看我们的贡献指南

本文由spring4all.com翻译小分队创作,采用知识共享-署名-非商业性使用-相同方式共享 4.0 国际 许可 协议进行许可。

评论 抢沙发

请登录后发表评论

    暂无评论内容