[原創(chuàng)]4.在Spring中使用JDBC訪問(wèn)關(guān)系型數(shù)據(jù)

實(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)伸但,與lambda expresion表達(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)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市更胖,隨后出現(xiàn)的幾起案子铛铁,更是在濱河造成了極大的恐慌,老刑警劉巖却妨,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饵逐,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡彪标,警方通過(guò)查閱死者的電腦和手機(jī)倍权,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)捞烟,“玉大人薄声,你說(shuō)我怎么就攤上這事√饣” “怎么了默辨?”我有些...
    開(kāi)封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)苍息。 經(jīng)常有香客問(wèn)我缩幸,道長(zhǎng),這世上最難降的妖魔是什么竞思? 我笑而不...
    開(kāi)封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任表谊,我火速辦了婚禮,結(jié)果婚禮上盖喷,老公的妹妹穿的比我還像新娘铃肯。我一直安慰自己,他們只是感情好传蹈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著步藕,像睡著了一般惦界。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咙冗,一...
    開(kāi)封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天沾歪,我揣著相機(jī)與錄音,去河邊找鬼雾消。 笑死灾搏,一個(gè)胖子當(dāng)著我的面吹牛挫望,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狂窑,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼媳板,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了泉哈?” 一聲冷哼從身側(cè)響起蛉幸,我...
    開(kāi)封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎丛晦,沒(méi)想到半個(gè)月后奕纫,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡烫沙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年匹层,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锌蓄。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡升筏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出煤率,到底是詐尸還是另有隱情仰冠,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布蝶糯,位于F島的核電站洋只,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏昼捍。R本人自食惡果不足惜识虚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望妒茬。 院中可真熱鬧担锤,春花似錦、人聲如沸乍钻。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)银择。三九已至多糠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間浩考,已是汗流浹背夹孔。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人搭伤。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓只怎,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親怜俐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子身堡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353