Skip to content

Latest commit

 

History

History
1354 lines (919 loc) · 32.6 KB

108.md

File metadata and controls

1354 lines (919 loc) · 32.6 KB

Spring JdbcTemplate教程

原文: http://zetcode.com/db/jdbctemplate/

Spring JdbcTemplate教程展示了如何使用 Spring 的JdbcTemplate处理数据。 我们是 MySQL 数据库。 我们创建使用JdbcTemplate的经典 Spring 和 Spring Boot 应用。 ZetCode 拥有用于 MySQL Java 的完整电子书,其中包含扩展的JdbcTemplate章节: MySQL Java 编程电子书

Tweet

目录

  1. 在 MySQL 中创建数据库
  2. Maven 依赖项
  3. queryForObject()方法
  4. RowMapper
  5. BeanPropertyRowMapper
  6. queryForList()方法
  7. 使用命名参数
  8. 使用JdbcTemplate的经典 Spring
  9. 使用JdbcTemplate的 Spring Boot

Spring

Spring 是流行的 Java 应用框架。 JdbcTemplate是用于简化 JDBC 编程的工具。 它处理乏味且容易出错的底层细节,例如处理事务,清理资源以及正确处理异常。 JdbcTemplate包含在 Spring 的spring-jdbc模块中。 Spring Boot 是 Spring 的解决方案,用于创建独立的,生产级的基于 Spring 的应用。

MySQL 是一个开源关系数据库管理系统。 它是最受欢迎的数据库之一。 它通常在 Web 应用中使用。

MySQL 创建数据库

我们使用mysql监视器创建一个新的testdb数据库。

cars_mysql.sql

DROP TABLE IF EXISTS cars;
CREATE TABLE cars(id INT PRIMARY KEY AUTO_INCREMENT,
                  name VARCHAR(255), price INTEGER) ENGINE=InnoDB;

INSERT INTO cars(name, price) VALUES('Audi', 52642);
INSERT INTO cars(name, price) VALUES('Mercedes', 57127);
INSERT INTO cars(name, price) VALUES('Skoda', 9000);
INSERT INTO cars(name, price) VALUES('Volvo', 29000);
INSERT INTO cars(name, price) VALUES('Bentley', 350000);
INSERT INTO cars(name, price) VALUES('Citroen', 21000);
INSERT INTO cars(name, price) VALUES('Hummer', 41400);
INSERT INTO cars(name, price) VALUES('Volkswagen', 21600);

这是在 MySQL 中创建cars表的 SQL。

要创建数据库和表,我们使用mysql监视工具。

$ sudo service mysql start

MySQL 用sudo service mysql start命令启动。

$ mysql -u user7 -p

我们使用mysql监视器连接到数据库。

mysql> CREATE DATABASE testdb;
Query OK, 1 row affected (0.02 sec)

使用CREATE DATABASE语句创建一个新数据库。

mysql> USE testdb;
mysql> SOURCE cars_mysql.sql

使用source命令,加载并执行cars_mysql.sql文件。

mysql> SELECT * FROM cars;
+----+------------+--------+
| id | name       | price  |
+----+------------+--------+
|  1 | Audi       |  52642 |
|  2 | Mercedes   |  57127 |
|  3 | Skoda      |   9000 |
|  4 | Volvo      |  29000 |
|  5 | Bentley    | 350000 |
|  6 | Citroen    |  21000 |
|  7 | Hummer     |  41400 |
|  8 | Volkswagen |  21600 |
+----+------------+--------+
8 rows in set (0.00 sec)

我们验证数据。

Maven 依赖

对于我们的应用,我们需要下载数据库驱动程序和 Spring 模块。 我们使用 Maven 做到这一点。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.1.3.RELEASE</version>
</dependency>

这将下载spring-jdbc模块。

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

这是 MySQL 驱动程序的 Maven 依赖关系。

queryForObject()方法

queryForObject()方法执行 SQL 查询并返回结果对象。 结果类型在参数中指定。

com/zetcode/SpringDBQueryObjectEx.java

package com.zetcode;

import java.sql.SQLException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;

public class SpringDBQueryObjectEx {

    public static void main(String[] args) throws SQLException {

        var ds = new SimpleDriverDataSource();
        ds.setDriver(new com.mysql.jdbc.Driver());
        ds.setUrl("jdbc:mysql://localhost:3306/testdb");
        ds.setUsername("user7");
        ds.setPassword("s$cret");

        var sql = "SELECT COUNT(*) FROM cars";

        var jtm = new JdbcTemplate(ds);
        int numOfCars = jtm.queryForObject(sql, Integer.class);

        System.out.format("There are %d cars in the table", numOfCars);
    }
}

在示例中,我们使用queryForObject()方法获取cars表中的汽车数量。

var sql = "SELECT COUNT(*) FROM cars";

该 SQL 返回cars表中的行数。

int numOfCars = jtm.queryForObject(sql, Integer.class);

queryForObject()方法的第二个参数指定结果的类型; 在我们的案例中是Integer

行映射器

RowMapper逐行映射结果集的行。 此接口的实现执行将每一行映射到结果对象的实际工作。

com/zetcode/model/Car.java

package com.zetcode.model;

import java.util.Objects;

public class Car {

    private Long id;
    private String name;
    private int price;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Car car = (Car) o;
        return price == car.price &&
                Objects.equals(id, car.id) &&
                Objects.equals(name, car.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, price);
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Car{");
        sb.append("id=").append(id);
        sb.append(", name='").append(name).append('\'');
        sb.append(", price=").append(price);
        sb.append('}');
        return sb.toString();
    }
}

我们有一个Car bean。 它具有idnameprice属性。

com/zetcode/SpringDBRowMapper.java

package com.zetcode;

import java.sql.ResultSet;
import java.sql.SQLException;

import com.zetcode.model.Car;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;

public class SpringDBRowMapper {

    public static void main(String[] args) throws SQLException {

        var ds = new SimpleDriverDataSource();
        ds.setDriver(new com.mysql.jdbc.Driver());
        ds.setUrl("jdbc:mysql://localhost:3306/testdb");
        ds.setUsername("user7");
        ds.setPassword("s$cret");

        var rm = (RowMapper<Car>) (ResultSet result, int rowNum) -> {

            var car = new Car();

            car.setId(result.getLong("id"));
            car.setName(result.getString("name"));
            car.setPrice(result.getInt("price"));

            return car;
        };

        var sql = "SELECT * FROM cars WHERE id=?";
        Long id = 1L;

        var jtm = new JdbcTemplate(ds);
        var car = (Car) jtm.queryForObject(sql, new Object[]{id}, rm);

        System.out.println(car);
    }
}

在示例中,我们使用RowMapper将结果集的行映射到Car对象。

var rm = (RowMapper<Car>) (ResultSet result, int rowNum) -> {

    var car = new Car();
    car.setId(result.getLong("id"));
    car.setName(result.getString("name"));
    car.setPrice(result.getInt("price"));

    return car;
};

这是结果集行到Car对象的映射。

var car = (Car) jtm.queryForObject(sql, new Object[] {id}, rm);

RowMapper的实例作为第三个参数传递到queryForObject()

BeanPropertyRowMapper

BeanPropertyRowMapper是一种RowMapper实现,可将行转换为指定映射目标类的新实例。 映射的目标类必须是顶级类,并且必须具有默认或无参数构造器。 结果集元数据中的列名与相应属性的公共设置器匹配。

com/zetcode/model/Car.java

package com.zetcode.model;

public class Car {

    private Long id;
    private String name;
    private int price;

    // getters and setters etc.
}

这是我们将cars表行映射到的Car bean。

com/zetcode/SpringBeanPropertyRowMapper.java

package com.zetcode;

import com.zetcode.model.Car;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;

import java.sql.SQLException;

public class SpringBeanPropertyRowMapper {

    public static void main(String[] args) throws SQLException {

        var dataSource = new SimpleDriverDataSource();

        dataSource.setDriver(new com.mysql.jdbc.Driver());
        dataSource.setUrl("jdbc:mysql://localhost:3306/testdb");
        dataSource.setUsername("user7");
        dataSource.setPassword("s$cret");

        var sql = "SELECT * FROM cars WHERE id=?";
        Long id = 1L;

        var jtm = new JdbcTemplate(dataSource);

        var car = (Car) jtm.queryForObject(sql, new Object[]{id},
                 BeanPropertyRowMapper.newInstance(Car.class));

        System.out.println(car);
    }
}

该示例连接到testdb数据库,并从cars表中检索一辆汽车。

var sql = "SELECT * FROM cars WHERE id=?";

该 SQL 语句从数据库中选择汽车对象。

var jtm = new JdbcTemplate(dataSource);

JdbcTemplate已创建; 它以数据源为参数。

var car = (Car) jtm.queryForObject(sql, new Object[]{id},
    BeanPropertyRowMapper.newInstance(Car.class));

使用queryForObject()方法,我们查询一个对象。 我们提供了 SQL 语句,参数和行映射器。 BeanPropertyRowMapper将一行转换为Car目标类的新实例。

System.out.println(car);

取回的汽车被打印到终端。

Car{id=1, name='Audi', price=52642}

应用从cars表中打印第一行。

queryForList()方法

queryForList()方法执行对结果列表的查询。 在以下示例中,我们从cars表中检索所有汽车。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │               SpringDBQueryForList.java
│   └───resourcesdb.properties
└───test
    └───java

这是项目结构。

我们将数据源属性放入db.properties文件。 最好将资源与 Java 文件分开。

resources/db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/testdb
jdbc.username=user7
jdbc.password=s$cret

这些是 MySQL 数据库的属性。

com/zetcode/SpringDBQueryForList.java

package com.zetcode;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;

import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Driver;
import java.util.List;
import java.util.Map;
import java.util.Properties;

public class SpringDBQueryForList {

    public static void main(String[] args) throws IOException,
            ClassNotFoundException {

        var prop = new Properties();
        prop.load(new FileInputStream("src/main/resources/db.properties"));

        var ds = new SimpleDriverDataSource();

        ds.setDriverClass(((Class<Driver>) Class.forName(prop.getProperty("jdbc.driver"))));
        ds.setUrl(prop.getProperty("jdbc.url"));
        ds.setUsername(prop.getProperty("jdbc.username"));
        ds.setPassword(prop.getProperty("jdbc.password"));

        var sql = "SELECT * FROM cars";

        var jtm = new JdbcTemplate(ds);
        var rows = (List<Map<String, Object>>) jtm.queryForList(sql);

        rows.forEach(System.out::println);
    }
}

该示例连接到 MySQL testdb数据库,并从cars表中检索所有行。

var prop = new Properties();
prop.load(new FileInputStream("src/main/resources/db.properties"));

数据源属性是从db.properties文件加载的。

var ds = new SimpleDriverDataSource();

ds.setDriverClass(((Class<Driver>) Class.forName(prop.getProperty("jdbc.driver"))));
ds.setUrl(prop.getProperty("jdbc.url"));
ds.setUsername(prop.getProperty("jdbc.username"));
ds.setPassword(prop.getProperty("jdbc.password"));

我们用属性填充SimpleDriverDataSource's属性。

var jtm = new JdbcTemplate(ds);
var rows = (List<Map<String, Object>>) jtm.queryForList(sql);

JdbcTemplatequeryForList()方法返回表中的行列表。

rows.forEach(System.out::println);

我们遍历列表并将数据打印到终端。

{id=1, name=Audi, price=52642}
{id=2, name=Mercedes, price=57127}
{id=3, name=Skoda, price=9000}
{id=4, name=Volvo, price=29000}
{id=5, name=Bentley, price=350000}
{id=6, name=Citroen, price=21000}
{id=7, name=Hummer, price=41400}
{id=8, name=Volkswagen, price=21600}

这是示例的输出。

使用命名参数

NamedParameterJdbcTemplate是具有一组基本 JDBC 操作的模板类,允许使用命名参数而不是传统的?占位符。

resources/db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/testdb
jdbc.username=user7
jdbc.password=s$cret

这些是 MySQL 数据库的属性。

com/zetcode/model/Car.java

package com.zetcode.model;

public class Car {

    private Long id;
    private String name;
    private int price;

    // getters and setters etc.
}

这是Car bean。

com/zetcode/SpringDBNamedParameters.java

package com.zetcode;

import com.zetcode.model.Car;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;

import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Driver;
import java.util.Properties;

public class SpringDBNamedParameters {

    public static void main(String[] args) throws IOException,
            ClassNotFoundException {

        var prop = new Properties();
        prop.load(new FileInputStream("src/main/resources/db.properties"));

        var ds = new SimpleDriverDataSource();
        ds.setDriverClass(((Class<Driver>) Class.forName(prop.getProperty("jdbc.driver"))));
        ds.setUrl(prop.getProperty("jdbc.url"));
        ds.setUsername(prop.getProperty("jdbc.username"));
        ds.setPassword(prop.getProperty("jdbc.password"));

        var sql = "SELECT * FROM cars WHERE name LIKE :name";
        var carName = "Volvo";

        var jtm = new NamedParameterJdbcTemplate(ds);

        var namedParams = new MapSqlParameterSource("name", carName);
        var car = (Car) jtm.queryForObject(sql, namedParams,
                BeanPropertyRowMapper.newInstance(Car.class));

        System.out.println(car);
    }
}

该示例查找汽车名称; 其 SQL 代码使用命名参数。

var sql = "SELECT * FROM cars WHERE Name LIKE :name";

SQL 具有:name令牌,这是一个命名参数。

var jtm = new NamedParameterJdbcTemplate(ds);

NamedParameterJdbcTemplate用于命名参数。

var namedParams = new MapSqlParameterSource("name", carName);

MapSqlParameterSource用于将参数值的简单映射传递给NamedParameterJdbcTemplate类的方法。

var car = (Car) jtm.queryForObject(sql, namedParams,
        BeanPropertyRowMapper.newInstance(Car.class));

命名的参数作为第二个参数传递给queryForObject()方法。

Car{id=4, name='Volvo', price=29000}

这是示例的输出。

使用JdbcTemplate的经典 Spring 示例

在下面的示例中,我们创建一个经典的命令行 Spring 应用,该应用使用JdbcTemplate连接到数据库并发出 SQL 语句。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   ClassicSpringJdbcTemplate.java
│   │           ├───config
│   │           │       DBConfig.java
│   │           ├───model
│   │           │       Car.java
│   │           └───service
│   │                   CarService.java
│   │                   ICarService.java
│   └───resourcesdb.properties
└───test
    └───java

这是项目结构。

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>com.zetcode</groupId>
    <artifactId>classicspringex</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring-version>5.1.3.RELEASE</spring-version>

    </properties>

    <dependencies>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring-version}</version>
        </dependency>

    </dependencies>

</project>

Maven pom.xml文件包含 MySQL 驱动程序,核心 Spring 库和 JdbcTemplate 的依赖项。

com/zetcode/model/Car.java

package com.zetcode.model;

public class Car {

    private Long id;
    private String name;
    private int price;

    // getters and setters etc.
}

这是Car bean。

resources/db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/testdb
jdbc.username=user7
jdbc.password=s$cret

这些是数据库属性。

com/zetcode/config/DBConfig.java

package com.zetcode.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;

@Configuration
@PropertySource(value = "classpath:db.properties", ignoreResourceNotFound = true)
public class DBConfig {

    @Autowired
    private Environment env;

    @Bean
    public DataSource dataSource() {

        var dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty("jdbc.driver"));
        dataSource.setUrl(env.getProperty("jdbc.url"));
        dataSource.setUsername(env.getProperty("jdbc.username"));
        dataSource.setPassword(env.getProperty("jdbc.password"));

        return dataSource;
    }

    @Bean
    public JdbcTemplate jdbcTemplate() {

        var template = new JdbcTemplate();
        template.setDataSource(dataSource());

        return template;
    }
}

DBConfig生成两个 bean:dataSourcejdbcTemplate。 从db.properties中读取数据库属性。

com/zetcode/service/ICarService.java

package com.zetcode.service;

import com.zetcode.model.Car;

import java.util.List;

public interface ICarService {

    Car findById(Long id);
    List<Car> all();
}

ICarService定义了两种签约方法:findById()all()

com/zetcode/service/CarService.java

package com.zetcode.service;

import com.zetcode.model.Car;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class CarService implements ICarService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public List<Car> all() {

        return jdbcTemplate.query("SELECT * FROM cars",
                BeanPropertyRowMapper.newInstance(Car.class));
    }

    public Car findById(Long id) {

        var sql = "SELECT * FROM cars WHERE id=?";

        return jdbcTemplate.queryForObject(sql, new Object[]{id},
                BeanPropertyRowMapper.newInstance(Car.class));
    }
}

CarService具有与JdbcTemplate一起使用的代码。

@Autowired
private JdbcTemplate jdbcTemplate;

Spring 允许使用@Autowired注入依赖项。 使用字段注入,我们添加了DBConfig中生成的jdbcTemplate bean。

com/zetcode/ClassicSpringJdbcTemplate.java

package com.zetcode;

import com.zetcode.model.Car;
import com.zetcode.service.ICarService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan("com.zetcode")
public class ClassicSpringJdbcTemplate {

    public static void main(String[] args) {

        var ctx = new AnnotationConfigApplicationContext(ClassicSpringJdbcTemplate.class);
        var app = ctx.getBean(ClassicSpringJdbcTemplate.class);

        app.run();

        ctx.close();
    }

    @Autowired
    private ICarService carService;

    private void run() {

        System.out.println("Fetching a car with Id 3");
        Long id = 3L;
        var car = (Car) carService.findById(id);
        System.out.println(car);

        System.out.println("Fetching all cars");
        var cars = carService.all();
        cars.forEach(System.out::println);
    }
}

该示例使用JdbcTemplate从表中检索特定行和所有行。

var ctx = new AnnotationConfigApplicationContext(ClassicSpringJdbcTemplate.class);

AnnotationConfigApplicationContext允许创建带有特定注解的 Spring bean,例如@Service@Configuration

@Autowired
private CarService carService;

数据库功能委托给CarService,并随同@Autowired一起注入。

private void run() {

    System.out.println("Fetching a car with Id 3");
    Long id = 3L;
    var car = (Car) carService.findById(id);
    System.out.println(car);

    System.out.println("Fetching all cars");
    var cars = carService.all();
    cars.forEach(System.out::println);
}

我们调用服务方法来获取特定行并获取所有行。

Fetching a car with Id 3
Car{id=3, name='Skoda', price=9000}
Fetching all cars
Car{id=1, name='Audi', price=52642}
Car{id=2, name='Mercedes', price=57127}
Car{id=3, name='Skoda', price=9000}
Car{id=4, name='Volvo', price=29000}
Car{id=5, name='Bentley', price=350000}
Car{id=6, name='Citroen', price=21000}
Car{id=7, name='Hummer', price=41400}
Car{id=8, name='Volkswagen', price=21600}

这是输出。

使用JdbcTemplate的 Spring Boot 示例

在这个例子中,我们创建一个命令行 Spring Boot 应用,它将使用JdbcTemplate连接到数据库。 我们将有两个数据源:一个用于 Derby,一个用于 MySQL。 该项目可在作者的 Github 页面上找到。

pom.xml
src
├───main
│   ├───java
│   │   └───com
│   │       └───zetcode
│   │           │   Application.java
│   │           │   MyRunner.java
│   │           ├───config
│   │           │       AppConfig.java
│   │           ├───model
│   │           │       Car.java
│   │           ├───repository
│   │           │       CarRepository.java
│   │           │       ICarRepository.java
│   │           └───service
│   │                   CarService.java
│   │                   ICarService.java
│   └───resourcesapplication.properties
└───test
    └───java

这是项目结构。

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>com.zetcode</groupId>
    <artifactId>springbootjdbctemplate</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

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

    <dependencies>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

    </dependencies>

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

pom.xml文件包含 Spring Boot 和 MySQL 的依赖项。

resources/application.properties

mysql.datasource.driverClassName=com.mysql.jdbc.Driver
mysql.datasource.jdbcUrl=jdbc:mysql://localhost:3306/testdb
mysql.datasource.username=user7
mysql.datasource.password=s$cret

application.properties文件中,我们定义 MySQL 数据源。

com/zetcode/config/AppConfig.java

package com.zetcode.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class AppConfig {

    @Bean
    @ConfigurationProperties(prefix = "mysql.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
}

AppConfig中,我们使用DataSourceBuilder创建一个 MySQL 数据源。

com/zetcode/model/Car.java

package com.zetcode.model;

public class Car {

    private Long id;
    private String name;
    private int price;

    // getters and setters etc.
}

这是Car bean。

com/zetcode/repository/ICarRepository.java

package com.zetcode.repository;

import com.zetcode.model.Car;

import java.util.List;

public interface ICarRepository {

    void saveCar(Car car);
    Car findCarByName(String name);
    List<Car> findAll();
}

ICarRepository包含以下方法:保存新车,以其名称取回汽车并取回所有汽车。

com/zetcode/repository/CarRepository.java

package com.zetcode.repository;

import com.zetcode.model.Car;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class CarRepository implements ICarRepository {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void saveCar(Car car) {

        var sql = "INSERT INTO cars(name, price) VALUES (?, ?)";
        Object[] params = new Object[] {car.getName(), car.getPrice()};

        jdbcTemplate.update(sql, params);
    }

    @Override
    public Car findCarByName(String name) {

        var sql = "SELECT * FROM cars WHERE name = ?";
        Object[] param = new Object[] {name};

        return jdbcTemplate.queryForObject(sql, param,
                BeanPropertyRowMapper.newInstance(Car.class));
    }

    @Override
    public List<Car> findAll() {

        var sql = "SELECT * FROM cars";

        return jdbcTemplate.query(sql, BeanPropertyRowMapper.newInstance(Car.class));
    }
}

CarRepository包含ICarRepository合同的实现。 这是与JdbcTemplate一起使用的层。

com/zetcode/service/ICarService.java

package com.zetcode.service;

import com.zetcode.model.Car;

import java.util.List;

public interface ICarService {

    Car findByName(String name);
    List<Car> findAll();
}

我们有两种合同服务方式。

com/zetcode/service/CarService.java

package com.zetcode.service;

import com.zetcode.model.Car;
import com.zetcode.repository.ICarRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class CarService implements ICarService {

    @Autowired
    private ICarRepository carRepository;

    public Car findByName(String name) {

        return carRepository.findCarByName(name);
    }

    public List<Car> findAll() {

        return carRepository.findAll();
    }
}

CarService包含ICarService合同的实现。 服务方法委托给ICarRepository

com/zetcode/MyRunner.java

package com.zetcode;

import com.zetcode.model.Car;
import com.zetcode.service.ICarService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.stereotype.Component;

@Component
public class MyRunner implements CommandLineRunner {

    @Autowired
    private ICarService carService;

    @Override
    public void run(String... args) {

        try {
            var car = carService.findByName("Citroen");
            System.out.println(car);

        } catch (EmptyResultDataAccessException e) {
            System.out.println("Car was not found");
        }

        var cars = carService.findAll();

        for (Car car: cars) {
            System.out.println(car);
        }
    }
}

Spring Boot 命令行应用必须实现CommandLineRunner接口。 我们将要执行的代码放入run()方法中。

@Autowired
private ICarService carService;

Spring 注入carService bean。

try {
    var car = carService.findByName("Citroen");
    System.out.println(car);

} catch (EmptyResultDataAccessException e) {
    System.out.println("Car was not found");
}

我们试图找到一辆名为雪铁龙的汽车。 如果没有这样的汽车,Spring 会抛出EmptyResultDataAccessException异常。

var cars = carService.findAll();

for (Car car: cars) {
    System.out.println(car);
}

我们使用findAll()方法从数据库中检索所有汽车。 数据被打印到控制台。

com/zetcode/Application.java

package com.zetcode;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {

        SpringApplication.run(Application.class, args);
    }
}

这是 Spring Boot 应用的入口。

在本教程中,我们介绍了 Spring 的JdbcTemplate模块。 我们创建了一个使用JdbcTemplate的 Spring Boot 应用。 ZetCode 具有以下相关教程: Java 教程Spring JdbcTemplate教程Spring EmbeddedDatabaseBuilder教程EclipseLink 教程Hibernate Derby 教程Servlet FreeMarker JdbcTemplate教程MySQL Java 教程PostgreSQL Java 教程