實(shí)現(xiàn)效果:
使用Spring的JdbcTemplate模板構(gòu)建一個(gè)應(yīng)用程序來(lái)訪問(wèn)存儲(chǔ)在關(guān)系數(shù)據(jù)庫(kù)中的數(shù)據(jù)狡门。
項(xiàng)目結(jié)構(gòu)
└── 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 https://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>2.1.6.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>
1.創(chuàng)建一個(gè)Customer對(duì)象
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
}
2.存儲(chǔ)和查詢數(shù)據(jù)
Spring提供了一個(gè)名為JdbcTemplate的模板類,可以輕松使用SQL關(guān)系數(shù)據(jù)庫(kù)和JDBC兽赁。 大多數(shù)JDBC代碼都陷入資源獲取骂束,連接管理传于,異常處理和一般錯(cuò)誤檢查之中碉克,這與代碼要實(shí)現(xiàn)的內(nèi)容完全無(wú)關(guān)顶考。 JdbcTemplate會(huì)完成所有這些工作赁还。 要做的就是專注于手頭的業(yè)務(wù)。
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()));
}
}
Spring Boot
支持H2
數(shù)據(jù)庫(kù)村怪,一種內(nèi)存中的關(guān)系數(shù)據(jù)庫(kù)引擎秽浇,并自動(dòng)創(chuàng)建連接。 因?yàn)槭褂玫氖?code>spring-jdbc甚负,所以Spring Boot
會(huì)自動(dòng)創(chuàng)建一個(gè)JdbcTemplate柬焕。@Autowired
注解JdbcTemplate字段自動(dòng)加載它并使其可用。
Application類實(shí)現(xiàn)了Spring Boot的CommandLineRunner
接口梭域,這意味著它將在加載完應(yīng)用后執(zhí)行run()
方法斑举。
首先,使用JdbcTemplate的execute
方法安裝一些DDL(數(shù)據(jù)庫(kù)模式定義語(yǔ)言DDL(Data Definition Language))
.
其次病涨,使用Java 8語(yǔ)法獲取字符串列表富玷,將它們拆分為Java數(shù)組中的firstname / lastname
對(duì)。
然后使用JdbcTemplate的
batchUpdate`方法在新創(chuàng)建的表中安裝一些記錄既穆。 方法的第一個(gè)參數(shù)是要執(zhí)行的sql語(yǔ)句赎懦,最后一個(gè)參數(shù)(Object的數(shù)組) 替換sql語(yǔ)中的“?”變量幻工。
對(duì)于單行插入励两,用JdbcTemplate的
insert
方法很好。 但對(duì)于多個(gè)批量插入囊颅,最好使用batchUpdate
当悔。
使用 ''?'' 綁定變量來(lái)避免SQL注入攻擊。
最后踢代,使用query
方法在表中搜索與條件匹配的記錄盲憎。 再次使用“?”為查詢創(chuàng)建參數(shù)胳挎,在調(diào)用時(shí)傳入實(shí)際值饼疙。 最后一個(gè)參數(shù)使用Java 8 lambda語(yǔ)法,表示將每個(gè)結(jié)果行轉(zhuǎn)換為新的Customer對(duì)象慕爬。
Java 8 lambdas能映射到單個(gè)方法接口宏多,如Spring的RowMapper
儿惫。 如果是Java 7或更早版本,需要插入匿名接口實(shí)現(xiàn)伸但,與lambdaexpresion
表達(dá)式包含的相同的方法肾请。
建立一個(gè)可執(zhí)行的 JAR
利用maven
打包war或者jar運(yùn)行,這里不做介紹.
java -jar target/gs-relational-data-access-0.1.0.jar
測(cè)試
運(yùn)行后將會(huì)出現(xiàn)類似下方的日志輸出:
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 : Started Application in 1.693 seconds (JVM running for 2.054)