Spring JdbcTemplate
最后修改于 2020 年 9 月 1 日
Spring JdbcTemplate 教程演示了如何使用 Spring 的 JdbcTemplate 来处理数据。我们使用 MySQL 数据库。我们创建了经典的 Spring 和 Spring Boot 应用程序,它们都使用 JdbcTemplate。ZetCode 提供了一本完整的 MySQL Java 电子书,其中包含一个扩展的 JdbcTemplate 章节:
。目录
Spring
Spring 是一个流行的 Java 应用程序框架。JdbcTemplate
是一个用于简化 JDBC 编程的工具。它负责处理繁琐且容易出错的底层细节,例如事务处理、资源清理和异常处理。JdbcTemplate
包含在 Spring 的 spring-jdbc
模块中。Spring Boot
是 Spring 旨在创建独立、生产级的 Spring 应用程序的解决方案。
MySQL 是一个开源的关系型数据库管理系统。它是最流行的数据库之一。它经常用于 Web 应用程序。
MySQL 创建数据库
我们使用 mysql
监视器创建一个新的 testdb
数据库。
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 查询并返回一个结果对象。结果类型在参数中指定。
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://: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
RowMapper
在行级别上将结果集行映射到对象。此接口的实现执行将每行映射到结果对象的实际工作。
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。它具有 id
、name
和 price
属性。
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://: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
实现,它将一行转换为指定映射目标类的新实例。映射目标类必须是顶层类,并且必须有一个默认或无参构造函数。结果集元数据中的列名与相应属性的公共 setter 匹配。
package com.zetcode.model; public class Car { private Long id; private String name; private int price; // getters and setters etc. }
这是我们将 cars
表行映射到的 Car
bean。
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://: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 │ └───resources │ db.properties └───test └───java
这是项目结构。
我们将数据源属性放在 db.properties
文件中。将资源与 Java 文件分开是更好的做法。
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://:3306/testdb jdbc.username=user7 jdbc.password=s$cret
这些是 MySQL 数据库的属性。
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
的属性。
var jtm = new JdbcTemplate(ds); var rows = (List<Map<String, Object>>) jtm.queryForList(sql);
JdbcTemplate
的 queryForList
方法从表中返回一个行列表。
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 操作的模板类,它允许使用命名参数而不是传统的 '?' 占位符。
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://:3306/testdb jdbc.username=user7 jdbc.password=s$cret
这些是 MySQL 数据库的属性。
package com.zetcode.model; public class Car { private Long id; private String name; private int price; // getters and setters etc. }
这是 Car
bean。
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
用于将参数值的简单 Map 传递给 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 │ └───resources │ db.properties └───test └───java
这是项目结构。
<?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 的依赖项。
package com.zetcode.model; public class Car { private Long id; private String name; private int price; // getters and setters etc. }
这是 Car
bean。
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://:3306/testdb jdbc.username=user7 jdbc.password=s$cret
这些是数据库属性。
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:dataSource
和 jdbcTemplate
。数据库属性从 db.properties
读取。
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
。
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。
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
允许使用 @Service
或 @Configuration
等特定注解创建 Spring bean。
@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 │ └───resources │ application.properties └───test └───java
这是项目结构。
<?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>8.0.20</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 的依赖项。
mysql.datasource.driverClassName=com.mysql.cj.jdbc.Driver mysql.datasource.jdbcUrl=jdbc:mysql://:3306/testdb?serverTimezone=UTC mysql.datasource.username=user7 mysql.datasource.password=s$cret
在 application.properties
文件中,我们定义了 MySQL 数据源。
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 数据源。
package com.zetcode.model; public class Car { private Long id; private String name; private int price; // getters and setters etc. }
这是 Car
bean。
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
包含保存新汽车、按名称获取汽车以及获取所有汽车的方法。
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 的层。
package com.zetcode.service; import com.zetcode.model.Car; import java.util.List; public interface ICarService { Car findByName(String name); List<Car> findAll(); }
我们有两个合约服务方法。
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
。
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"); }
我们尝试查找名称为 Citroen 的汽车。如果没有这样的汽车,Spring 将抛出 EmptyResultDataAccessException
异常。
var cars = carService.findAll(); for (Car car: cars) { System.out.println(car); }
我们使用 findAll
方法从数据库中检索所有汽车。数据被打印到控制台。
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 教程。