SpringBoot 中使用 JDBC Templet

前言

Spring 的 JDBC Templet 是 Spring 對 JDBC 使用的一個基本的封裝买猖。他主要是幫助程序員實現(xiàn)了數(shù)據庫連接的管理刁笙,其余的使用方式和直接使用 JDBC 沒有什么大的區(qū)別破花。

業(yè)務需求

JDBC 的使用大家都比較熟悉了。這里主要為了演示在 SpringBoot 中使用 Spring JDBC Templet 的步驟疲吸,所以我們就設計一個簡單的需求座每。一個用戶對象的 CURD 的操作。對象有兩個屬性摘悴,一個屬性是id峭梳,一個屬性是名稱。存儲在 MySQL 的 auth_user 表里面蹂喻。

新建項目和增加依賴

在 Intellij IDEA 里面新建一個空的 SpringBoot 項目葱椭。具體步驟參考
SpringBoot 的第一次邂逅。根據本樣例的需求口四,我們要添加下面三個依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>6.0.6</version>
</dependency>

因為要發(fā)布 Http Rest 的服務孵运,所以添加 spring-boot-starter-web 依賴,這里我們要使用 JDBC Tempet 方法來訪問數(shù)據庫蔓彩,所以添加了 spring-boot-starter-jdbc 依賴治笨,要訪問 MySQL 數(shù)據庫,所以添加了 MySQL 最新版本的 JDBC 驅動程序赤嚼。

準備數(shù)據庫環(huán)境

假定在 Linux 操作系統(tǒng)上已經安裝了 MySQL 5.7大磺。以下操作都是在操作系統(tǒng)的命令行中,通過 root 用戶登錄到 MySQL 的命令行客戶端中執(zhí)行的探膊。

建庫建表

create database springboot_jdbc;

create table auth_user (uuid bigint not null,name varchar(32), primary key (uuid)) default charset=utf8mb4;

設定用戶權限

grant all privileges on springboot_jdbc.* to 'springboot'@'%' identified by 'springboot';

flush privileges;

配置數(shù)據源(連接池)

SpringBoot 的數(shù)據源是自動配置的。在 SpringBoot 2.0 中待榔,有幾種數(shù)據源配置可選逞壁,他們按照 HikariCP -> Tomcat pooling -> Commons DBCP2 優(yōu)先順序來選擇最后實際使用哪個數(shù)據源流济。

在項目加入 spring-boot-starter-jdbc 依賴的時候,就已經包括了 HikariCP 數(shù)據源的依賴腌闯,所以這里自動配置 HikariCP 連接池數(shù)據源绳瘟。

在 appplications.properties 中增加如下的配置

#通用數(shù)據源配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://10.110.2.5:3306/spring-boot-jdbc?charset=utf8mb4&useSSL=false
spring.datasource.username=springboot
spring.datasource.password=springboot
# Hikari 數(shù)據源專用配置
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5

其中 Hikari 數(shù)據源的大部分配置如下圖。每個配置代表的含義可以自行查詢一下


Hikari 數(shù)據源配置

程序開發(fā)

用戶數(shù)據庫實體

根據需求姿骏,對應的用戶數(shù)據實體有兩個屬性糖声,一個是 id ,一個是 name 分瘦。這是一個純 POJO 對象蘸泻。

package com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao;

/**
 * 用戶實體對象
 *
 * @author 楊高超
 * @since 2018-03-09
 */
public class UserDO {
    private Long id;
    private String name;

    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;
    }
}

通用的 Http Rest 返回對象

通常在 Http Rest 接口中,我們不僅想直接返回業(yè)務對象的內容嘲玫,還要返回一些通用的信息悦施,例如接口調用的結果,調用失敗的時候返回的自定義文本消息等去团。那么我們就需要建立兩個通用的 rest 返回對象抡诞,除了返回通用的接口調用結果和文本消息,一個包括一個單獨的業(yè)務內容土陪,一個包含一個持有多個業(yè)務內容的集合昼汗。具體定義如下

單獨業(yè)務內容返回對象
package com.yanggaochao.springboot.learn.springbootjdbclearn.domain.bo;

/**
 * 單個對象返回結果
 *
 * @author 楊高超
 * @since 2018-03-09
 */
public class RestItemResult<T> {
    private String result;
    private String message;
    private T item;

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getItem() {
        return item;
    }

    public void setItem(T item) {
        this.item = item;
    }
}

集合業(yè)務內容返回對象
package com.yanggaochao.springboot.learn.springbootjdbclearn.domain.bo;

import java.util.Collection;

/**
 * 集合對象返回結果
 *
 * @author 楊高超
 * @since 2018-03-09
 */
public class RestCollectionResult<T> {
    private String result;
    private String message;
    private Collection<T> items;

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Collection<T> getItems() {
        return items;
    }

    public void setItems(Collection<T> items) {
        this.items = items;
    }
}

數(shù)據持久層開發(fā)

用戶數(shù)據持久層接口定義
package com.yanggaochao.springboot.learn.springbootjdbclearn.dao;

import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao.UserDO;

import java.util.List;

/**
 * 用戶數(shù)據層接口
 *
 * @author 楊高超
 * @since 2018-03-09
 */
public interface UserDao {
    /**
     * 向數(shù)據庫中保存一個新用戶
     *
     * @param user 要保存的用戶對象
     * @return 是否增肌成功
     */
    Boolean add(UserDO user);

    /**
     * 更新數(shù)據庫中的一個用戶
     *
     * @param user 要更新的用戶對象
     * @return 是否更新成功
     */
    Boolean update(UserDO user);

    /**
     * 刪除一個指定的用戶
     *
     * @param id 要刪除的用戶的標識
     * @return 是否刪除成功
     */
    boolean delete(Long id);

    /**
     * 精確查詢一個指定的用戶
     *
     * @param id 要查詢的用戶的標識
     * @return 如果能夠查詢到,返回用戶信息鬼雀,否則返回 null
     */
    UserDO locate(Long id);

    /**
     * 通過名稱模糊查詢用戶
     *
     * @param name 要模糊查詢的名稱
     * @return 查詢到的用戶列表
     */
    List<UserDO> matchName(String name);
}

用戶數(shù)據持久層實現(xiàn)

package com.yanggaochao.springboot.learn.springbootjdbclearn.dao.impl;

import com.yanggaochao.springboot.learn.springbootjdbclearn.dao.UserDao;
import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao.UserDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;

/**
 * 用戶對象數(shù)據庫訪問實現(xiàn)類
 *
 * @author 楊高超
 * @since 2018-03-09
 */
@Repository
public class UserDaoJDBCTempletImpl implements UserDao {
    private final JdbcTemplate jdbcTemplate;

    @Autowired
    public UserDaoJDBCTempletImpl(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public Boolean add(UserDO user) {
        String sql = "INSERT INTO AUTH_USER(UUID,NAME) VALUES(?,?)";
        return jdbcTemplate.update(sql, user.getId(), user.getName()) > 0;
    }

    @Override
    public Boolean update(UserDO user) {
        String sql = "UPDATE AUTH_USER SET NAME = ? WHERE UUID = ?";
        return jdbcTemplate.update(sql, user.getName(), user.getId()) > 0;
    }

    @Override
    public boolean delete(Long id) {
        String sql = "DELETE FROM AUTH_USER WHERE UUID = ?";
        return jdbcTemplate.update(sql, id) > 0;

    }

    @Override
    public UserDO locate(Long id) {
        String sql = "SELECT * FROM AUTH_USER WHERE UUID=?";
        SqlRowSet rs = jdbcTemplate.queryForRowSet(sql, id);

        if (rs.next()) {
            return generateEntity(rs);
        }
        return null;
    }

    @Override
    public List<UserDO> matchName(String name) {
        String sql = "SELECT * FROM AUTH_USER WHERE NAME LIKE ?";
        SqlRowSet rs = jdbcTemplate.queryForRowSet(sql, "%" + name + "%");
        List<UserDO> users = new ArrayList<>();
        while (rs.next()) {
            users.add(generateEntity(rs));
        }
        return users;
    }

    private UserDO generateEntity(SqlRowSet rs) {
        UserDO weChatPay = new UserDO();
        weChatPay.setId(rs.getLong("UUID"));
        weChatPay.setName(rs.getString("NAME"));
        return weChatPay;
    }
}

這里首先用一個注解 @Repository 表示這是一個數(shù)據持久層的類顷窒,SpringBoot 將自動將這個類實例化。然后在構造函數(shù)上增加一個 @Autowired 取刃,SpringBoot 在實例化這個類的時候蹋肮,會自動將 JDBCTemplet 實例注入到這個類里面。這里 JDBCTemplet 實例是 SpringBoot 根據 applications.properties 中數(shù)據源相關的配置自動配置出來的璧疗。按照 SpringBoot 自動配置數(shù)據源的算法坯辩,這里將會配置的數(shù)據源是 HikariCP。

剩下的則和普通的 Spring JDBCTemplet 開發(fā)一樣崩侠,通過程序員手動在對象和數(shù)據庫 SQL 之間進行轉換漆魔,實現(xiàn)了用戶的增加、修改却音、刪除改抡、模糊匹配、精確查詢等功能系瓢。

數(shù)據業(yè)務層開發(fā)

數(shù)據業(yè)務層接口定義
package com.yanggaochao.springboot.learn.springbootjdbclearn.service;

import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao.UserDO;

import java.util.List;

/**
 * 用戶服務層接口
 *
 * @author 楊高超
 * @since 2018-03-09
 */
public interface UserService {
    
    UserDO add(UserDO user);

    UserDO update(UserDO user);

    boolean delete(Long id);

    UserDO locate(Long id);

    List<UserDO> matchName(String name);
}

數(shù)據業(yè)務層實現(xiàn)
package com.yanggaochao.springboot.learn.springbootjdbclearn.service.impl;

import com.yanggaochao.springboot.learn.springbootjdbclearn.dao.UserDao;
import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao.UserDO;
import com.yanggaochao.springboot.learn.springbootjdbclearn.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * 用戶業(yè)務層實現(xiàn)類
 *
 * @author 楊高超
 * @since 2018-03-09
 */
@Service
public class UserServiceImpl implements UserService {
    private final UserDao userDao;

    @Autowired
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public UserDO add(UserDO user) {
        user.setId(new Date().getTime());
        if (userDao.add(user)) {
            return user;
        }
        return null;
    }

    @Override
    public UserDO update(UserDO user) {
        if (userDao.update(user)) {
            return locate(user.getId());
        }
        return null;
    }

    @Override
    public boolean delete(Long id) {
        return userDao.delete(id);
    }

    @Override
    public UserDO locate(Long id) {
        return userDao.locate(id);
    }

    @Override
    public List<UserDO> matchName(String name) {
        return userDao.matchName(name);
    }
}

這里通過一個 @Service 注解聲明這個實現(xiàn)類是一個業(yè)務層的類阿纤。持久層的 UserDao 通過 @Autowired 讓 SpringBoot 實例化這個業(yè)務層類的時候,自動將對應的持久層類注入到這個業(yè)務類中夷陋。

這里在增加用戶對象的時候欠拾,給用戶設定標識的時候胰锌,簡單的用了一個當前時間的毫秒數(shù)作為標識。實際開發(fā)的過程中藐窄,這個地方需要用一個保證全局唯一的機制來保證這個標識不能重復资昧。

對外服務層開發(fā)

package com.yanggaochao.springboot.learn.springbootjdbclearn.web;

import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.bo.RestCollectionResult;
import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.bo.RestItemResult;
import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao.UserDO;
import com.yanggaochao.springboot.learn.springbootjdbclearn.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 用戶 Http Rest 接口
 *
 * @author 楊高超
 * @since 2018-03-09
 */
@RestController
@RequestMapping("api/v1/user")
public class UserApi {
    @Autowired
    private UserService userService;

    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public RestItemResult<UserDO> add(@RequestBody UserDO user) {
        RestItemResult<UserDO> result = new RestItemResult<>();
        user = userService.add(user);
        if (user != null) {
            result.setItem(user);
            result.setResult("success");
        } else {
            result.setMessage("新增用戶失敗");
            result.setResult("failure");
        }
        return result;
    }

    @RequestMapping(value = "/update", method = RequestMethod.POST)
    public RestItemResult<UserDO> update(@RequestBody UserDO user) {
        RestItemResult<UserDO> result = new RestItemResult<>();
        user = userService.update(user);
        if (user != null) {
            result.setItem(user);
            result.setResult("success");
        } else {
            result.setMessage("修改用戶失敗");
            result.setResult("failure");
        }
        return result;
    }

    @RequestMapping(value = "/delete/{uuid}", method = RequestMethod.GET)
    public RestItemResult<UserDO> delete(@PathVariable Long uuid) {
        RestItemResult<UserDO> result = new RestItemResult<>();
        if (userService.delete(uuid)) {
            result.setResult("success");
        } else {
            result.setMessage("刪除用戶失敗");
            result.setResult("failure");
        }
        return result;
    }

    @RequestMapping(value = "/locate/{uuid}", method = RequestMethod.GET)
    public RestItemResult<UserDO> locate(@PathVariable Long uuid) {
        RestItemResult<UserDO> result = new RestItemResult<>();
        UserDO user = userService.locate(uuid);
        if (user != null) {
            result.setItem(user);
            result.setResult("success");
        } else {
            result.setMessage("查詢用戶失敗");
            result.setResult("failure");
        }
        return result;
    }

    @RequestMapping(value = "/match/{name}", method = RequestMethod.GET)
    public RestCollectionResult<UserDO> match(@PathVariable String name) {
        RestCollectionResult<UserDO> result = new RestCollectionResult<>();
        List<UserDO> users = userService.matchName(name);
        result.setItems(users);
        result.setResult("success");
        return result;
    }
}

這里 @RestController 用來聲明這是一個 Http Rest 接口類。通過類上的 @RequestMapping 和方法上的 @RequestMapping組合形成每個接口的調用路由荆忍。方法上的 @RequestMapping 中的 method 屬性聲明了 http 調用的方法格带。 @RequestBody 注解自動將 post 數(shù)據中的 json 對象轉成 POJO 對象。@PathVariable 將 http url 路徑中的數(shù)據自動轉換成為服務方法的參數(shù)刹枉。

Http Rest 接口測試

測試通過 Apache commons的 HttpClient 來調用 Http Rest 服務叽唱。

Http Resst 調用輔助類

package com.yanggaochao.springboot.learn.springbootjdbclearn;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpMethodParams;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Map;

/**
 * @author 楊高超
 * @since 2018-03-09
 */
public class HttpClientHelper {


    /**
     * 用 get 方法發(fā)起一個http請求
     *
     * @param url 要訪問的 http 的 url
     * @return 訪問 http 后得到的回應文本
     */
    public String httpGetRequest(String url, Map<String, String> headers) {
        try {
            HttpClient httpclient = new HttpClient();
            GetMethod method = new GetMethod(url);
            method.setRequestHeader("Content-Type", "application/json; charset=utf-8");
            method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                    new DefaultHttpMethodRetryHandler(3, false));
            if (headers != null) {
                for (String key : headers.keySet()) {
                    method.setRequestHeader(key, headers.get(key));
                }
            }

            int statusCode = httpclient.executeMethod(method);
            if (statusCode == 200) {
                return parseInputStream(method.getResponseBodyAsStream());
            } else {
                System.out.println(url + " status = " + statusCode);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 用 post 方法發(fā)起一個 http 請求
     *
     * @param url  要訪問的 http 的 url
     * @param data post 請求中的 data 數(shù)據
     * @return 訪問 http 后得到的回應文本
     */

    public String httpPostRequest(String url, String data, Map<String, String> headers) {
        try {
            HttpClient httpclient = new HttpClient();
            PostMethod method = new PostMethod(url);
            method.setRequestHeader("Content-Type",
                    "application/json;charset=UTF-8");
            method.setRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36");
            if (headers != null) {
                for (String key : headers.keySet()) {
                    method.setRequestHeader(key, headers.get(key));
                }
            }

            method.setRequestEntity(new StringRequestEntity(data, "json", "utf-8"));
            int statusCode = httpclient.executeMethod(method);
            if (statusCode == 200) {
                return parseInputStream(method.getResponseBodyAsStream());
            } else {
                System.out.println(url + " status = " + statusCode + parseInputStream(method.getResponseBodyAsStream()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 從 java.io.Reader 中解析文本數(shù)據
     *
     * @param rd java.io.Reader 對象
     * @throws Exception 發(fā)生錯誤時拋出異常
     */
    private String parseReader(Reader rd) throws Exception {
        BufferedReader brd = new BufferedReader(rd);
        String line;
        StringBuilder respongseContext = new StringBuilder();

        while ((line = brd.readLine()) != null) {
            respongseContext.append(line).append("\n");
        }
        //rd.close();
        if (respongseContext.length() > 0) {
            respongseContext.deleteCharAt(respongseContext.length() - 1);
        }
        return respongseContext.toString();
    }

    /**
     * 從輸入流中解析文本數(shù)據
     *
     * @param is 輸入流
     * @throws Exception 發(fā)生錯誤時拋出異常
     */
    private String parseInputStream(InputStream is) throws Exception {
        return parseReader(new BufferedReader(new InputStreamReader(is)));
    }

}

這里主要是實現(xiàn)了用 GET 和 POST 方法調用 Http Rest 服務的方法。

測試用例

采用 JUnit 來執(zhí)行測試用例嘶卧。為了實現(xiàn)測試尔觉,我們額外增加了下面的 maven 依賴

<dependency>
    <groupId>commons-httpclient</groupId>
    <artifactId>commons-httpclient</artifactId>
    <version>3.1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.codehaus.jettison</groupId>
    <artifactId>jettison</artifactId>
    <version>1.3.3</version>
    <scope>test</scope>
</dependency>
package com.yanggaochao.springboot.learn.springbootjdbclearn;

import org.codehaus.jettison.json.JSONObject;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * Description:
 *
 * @author 楊高超
 * @since 2018-03-09
 */
public class UserApiTest {
    private String userAddUrl = "http://localhost:3030/security/api/v1/user/add";
    private String userLocateUrl = "http://localhost:3030/security/api/v1/user/locate/";
    private String userDeleteUrl = "http://localhost:3030/security/api/v1/user/delete/";
    private String userUpdateUrl = "http://localhost:3030/security/api/v1/user/update";
    private String userMatchUrl = "http://localhost:3030/security/api/v1/user/match/";
    JSONObject addUser = new JSONObject();
    Long addUserId = null;

    List<Long> userIds = new ArrayList<>();

    @Before
    public void before() throws Exception {
        addUser.put("name", "美羊羊");
        JSONObject addResultJson = new JSONObject(new HttpClientHelper().httpPostRequest(userAddUrl, addUser.toString(), null));
        assert ("success".equals(addResultJson.getString("result")));
        addUserId = addResultJson.getJSONObject("item").getLong("id");

        JSONObject user = new JSONObject();
        user.put("name", "喜羊羊");
        addResultJson = new JSONObject(new HttpClientHelper().httpPostRequest(userAddUrl, user.toString(), null));
        assert ("success".equals(addResultJson.getString("result")));
        userIds.add(addResultJson.getJSONObject("item").getLong("id"));
        user.put("name", "灰太狼");
        addResultJson = new JSONObject(new HttpClientHelper().httpPostRequest(userAddUrl, user.toString(), null));
        assert ("success".equals(addResultJson.getString("result")));
        userIds.add(addResultJson.getJSONObject("item").getLong("id"));
    }

    @Test
    public void testUpdateUser() throws Exception {
        JSONObject user = new JSONObject();
        user.put("name", "霉羊羊");
        user.put("id", addUserId);
        new HttpClientHelper().httpPostRequest(userUpdateUrl, user.toString(), null);
        JSONObject locateResultJson = new JSONObject(new HttpClientHelper().httpGetRequest(userLocateUrl + addUserId, null));
        assert (user.getString("name").equals(locateResultJson.getJSONObject("item").getString("name")));
    }


    @Test
    public void testMatchUser() throws Exception {
        JSONObject matchResultJson = new JSONObject(new HttpClientHelper().httpGetRequest(userMatchUrl + URLEncoder.encode("羊","UTF-8"), null));
        assert (matchResultJson.has("items") && matchResultJson.getJSONArray("items").length() == 2);
        matchResultJson = new JSONObject(new HttpClientHelper().httpGetRequest(userMatchUrl + URLEncoder.encode("狼","UTF-8"), null));
        assert (matchResultJson.has("items") && matchResultJson.getJSONArray("items").length() == 1);
    }

    @After
    public void after() throws Exception {
        if (addUserId != null) {
            JSONObject deleteResultJson = new JSONObject(new HttpClientHelper().httpGetRequest(userDeleteUrl + addUserId, null));
            assert ("success".equals(deleteResultJson.getString("result")));
        }

        for (Long userId : userIds) {
            JSONObject deleteResultJson = new JSONObject(new HttpClientHelper().httpGetRequest(userDeleteUrl + userId, null));
            assert ("success".equals(deleteResultJson.getString("result")));
        }
    }
}

這里在 @Test 聲明了兩個測試用例,一個測試了用戶修改功能芥吟,一個測試了用戶模糊查詢功能侦铜。 @Before 聲明了在執(zhí)行每個測試用例之前要做的準備工作。這里首先往數(shù)據庫中插入三條數(shù)據钟鸵,同時也測試了數(shù)據的增加功能钉稍、精確查詢的功能。@After 聲明了執(zhí)行每個測試用例后的清理工作棺耍。這里主要是將之前插入的數(shù)據給刪除了贡未。這里同步測試了用戶刪除的功能。

后記

這里就展示了一個完整的 SpringBoot 使用 JDBC Templet 的完整樣例蒙袍。如果有在 Spring 下使用 JDBC Templet 的經歷俊卤,那么在 Spring 里面主要是減少了很多配置的工作。

本文設計的代碼已經上傳到 GitHUB 上害幅。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末消恍,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子以现,更是在濱河造成了極大的恐慌狠怨,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邑遏,死亡現(xiàn)場離奇詭異佣赖,居然都是意外死亡,警方通過查閱死者的電腦和手機记盒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門憎蛤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人纪吮,你說我怎么就攤上這事俩檬±覆颍” “怎么了?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵豆胸,是天一觀的道長。 經常有香客問我巷疼,道長晚胡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任嚼沿,我火速辦了婚禮估盘,結果婚禮上,老公的妹妹穿的比我還像新娘骡尽。我一直安慰自己遣妥,他們只是感情好,可當我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布攀细。 她就那樣靜靜地躺著箫踩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谭贪。 梳的紋絲不亂的頭發(fā)上境钟,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天,我揣著相機與錄音俭识,去河邊找鬼慨削。 笑死,一個胖子當著我的面吹牛套媚,可吹牛的內容都是我干的缚态。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼堤瘤,長吁一口氣:“原來是場噩夢啊……” “哼玫芦!你這毒婦竟也來了?” 一聲冷哼從身側響起宙橱,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤姨俩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后师郑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體环葵,經...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年宝冕,在試婚紗的時候發(fā)現(xiàn)自己被綠了张遭。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡地梨,死狀恐怖菊卷,靈堂內的尸體忽然破棺而出缔恳,到底是詐尸還是另有隱情,我是刑警寧澤洁闰,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布歉甚,位于F島的核電站,受9級特大地震影響扑眉,放射性物質發(fā)生泄漏纸泄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一腰素、第九天 我趴在偏房一處隱蔽的房頂上張望聘裁。 院中可真熱鬧,春花似錦弓千、人聲如沸衡便。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽镣陕。三九已至,卻和暖如春捌显,著一層夾襖步出監(jiān)牢的瞬間茁彭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工扶歪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留理肺,地道東北人。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓善镰,卻偏偏與公主長得像妹萨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子炫欺,可洞房花燭夜當晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內容