Spring Boot中使用JDBC Templet的方法教程
前言
Spring 的 JDBC Templet 是 Spring 對 JDBC 使用的一個(gè)基本的封裝。他主要是幫助程序員實(shí)現(xiàn)了數(shù)據(jù)庫連接的管理,其余的使用方式和直接使用 JDBC 沒有什么大的區(qū)別。
業(yè)務(wù)需求
JDBC 的使用大家都比較熟悉了。這里主要為了演示在 SpringBoot 中使用 Spring JDBC Templet 的步驟,所以我們就設(shè)計(jì)一個(gè)簡單的需求。一個(gè)用戶對象的 CURD 的操作。對象有兩個(gè)屬性,一個(gè)屬性是id,一個(gè)屬性是名稱。存儲(chǔ)在 MySQL 的 auth_user 表里面。
新建項(xiàng)目和增加依賴
在 Intellij IDEA 里面新建一個(gè)空的 SpringBoot 項(xiàng)目。具體步驟參考
Intellij IDEA創(chuàng)建spring-boot項(xiàng)目的圖文教程。根據(jù)本樣例的需求,我們要添加下面三個(gè)依賴
<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>
因?yàn)橐l(fā)布 Http Rest 的服務(wù),所以添加 spring-boot-starter-web 依賴,這里我們要使用 JDBC Tempet 方法來訪問數(shù)據(jù)庫,所以添加了 spring-boot-starter-jdbc 依賴,要訪問 MySQL 數(shù)據(jù)庫,所以添加了 MySQL 最新版本的 JDBC 驅(qū)動(dòng)程序。
準(zhǔn)備數(shù)據(jù)庫環(huán)境
假定在 Linux 操作系統(tǒng)上已經(jī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;
設(shè)定用戶權(quán)限
grant all privileges on springboot_jdbc.* to 'springboot'@'%' identified by 'springboot'; flush privileges;
配置數(shù)據(jù)源(連接池)
SpringBoot 的數(shù)據(jù)源是自動(dòng)配置的。在 SpringBoot 2.0 中,有幾種數(shù)據(jù)源配置可選,他們按照 HikariCP -> Tomcat pooling -> Commons DBCP2 優(yōu)先順序來選擇最后實(shí)際使用哪個(gè)數(shù)據(jù)源。
在項(xiàng)目加入 spring-boot-starter-jdbc 依賴的時(shí)候,就已經(jīng)包括了 HikariCP 數(shù)據(jù)源的依賴,所以這里自動(dòng)配置 HikariCP 連接池?cái)?shù)據(jù)源。
在 appplications.properties 中增加如下的配置
#通用數(shù)據(jù)源配置 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ù)據(jù)源專用配置 spring.datasource.hikari.maximum-pool-size=20 spring.datasource.hikari.minimum-idle=5
其中 Hikari 數(shù)據(jù)源的大部分配置如下圖。每個(gè)配置代表的含義可以自行查詢一下
程序開發(fā)
用戶數(shù)據(jù)庫實(shí)體
根據(jù)需求,對應(yīng)的用戶數(shù)據(jù)實(shí)體有兩個(gè)屬性,一個(gè)是 id ,一個(gè)是 name 。這是一個(gè)純 POJO 對象。
package com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao; /** * 用戶實(shí)體對象 * * @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è)務(wù)對象的內(nèi)容,還要返回一些通用的信息,例如接口調(diào)用的結(jié)果,調(diào)用失敗的時(shí)候返回的自定義文本消息等。那么我們就需要建立兩個(gè)通用的 rest 返回對象,除了返回通用的接口調(diào)用結(jié)果和文本消息,一個(gè)包括一個(gè)單獨(dú)的業(yè)務(wù)內(nèi)容,一個(gè)包含一個(gè)持有多個(gè)業(yè)務(wù)內(nèi)容的集合。具體定義如下
單獨(dú)業(yè)務(wù)內(nèi)容返回對象
package com.yanggaochao.springboot.learn.springbootjdbclearn.domain.bo; /** * 單個(gè)對象返回結(jié)果 * * @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è)務(wù)內(nèi)容返回對象
package com.yanggaochao.springboot.learn.springbootjdbclearn.domain.bo; import java.util.Collection; /** * 集合對象返回結(jié)果 * * @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ù)據(jù)持久層開發(fā)
用戶數(shù)據(jù)持久層接口定義
package com.yanggaochao.springboot.learn.springbootjdbclearn.dao; import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao.UserDO; import java.util.List; /** * 用戶數(shù)據(jù)層接口 * * @author 楊高超 * @since 2018-03-09 */ public interface UserDao { /** * 向數(shù)據(jù)庫中保存一個(gè)新用戶 * * @param user 要保存的用戶對象 * @return 是否增肌成功 */ Boolean add(UserDO user); /** * 更新數(shù)據(jù)庫中的一個(gè)用戶 * * @param user 要更新的用戶對象 * @return 是否更新成功 */ Boolean update(UserDO user); /** * 刪除一個(gè)指定的用戶 * * @param id 要?jiǎng)h除的用戶的標(biāo)識(shí) * @return 是否刪除成功 */ boolean delete(Long id); /** * 精確查詢一個(gè)指定的用戶 * * @param id 要查詢的用戶的標(biāo)識(shí) * @return 如果能夠查詢到,返回用戶信息,否則返回 null */ UserDO locate(Long id); /** * 通過名稱模糊查詢用戶 * * @param name 要模糊查詢的名稱 * @return 查詢到的用戶列表 */ List<UserDO> matchName(String name); }
用戶數(shù)據(jù)持久層實(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ù)據(jù)庫訪問實(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; } }
這里首先用一個(gè)注解 @Repository 表示這是一個(gè)數(shù)據(jù)持久層的類,SpringBoot 將自動(dòng)將這個(gè)類實(shí)例化。然后在構(gòu)造函數(shù)上增加一個(gè) @Autowired ,SpringBoot 在實(shí)例化這個(gè)類的時(shí)候,會(huì)自動(dòng)將 JDBCTemplet 實(shí)例注入到這個(gè)類里面。這里 JDBCTemplet 實(shí)例是 SpringBoot 根據(jù) applications.properties 中數(shù)據(jù)源相關(guān)的配置自動(dòng)配置出來的。按照 SpringBoot 自動(dòng)配置數(shù)據(jù)源的算法,這里將會(huì)配置的數(shù)據(jù)源是 HikariCP。
剩下的則和普通的 Spring JDBCTemplet 開發(fā)一樣,通過程序員手動(dòng)在對象和數(shù)據(jù)庫 SQL 之間進(jìn)行轉(zhuǎn)換,實(shí)現(xiàn)了用戶的增加、修改、刪除、模糊匹配、精確查詢等功能。
數(shù)據(jù)業(yè)務(wù)層開發(fā)
數(shù)據(jù)業(yè)務(wù)層接口定義
package com.yanggaochao.springboot.learn.springbootjdbclearn.service; import com.yanggaochao.springboot.learn.springbootjdbclearn.domain.dao.UserDO; import java.util.List; /** * 用戶服務(wù)層接口 * * @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ù)據(jù)業(yè)務(wù)層實(shí)現(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è)務(wù)層實(shí)現(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); } }
這里通過一個(gè) @Service 注解聲明這個(gè)實(shí)現(xiàn)類是一個(gè)業(yè)務(wù)層的類。持久層的 UserDao 通過 @Autowired 讓 SpringBoot 實(shí)例化這個(gè)業(yè)務(wù)層類的時(shí)候,自動(dòng)將對應(yīng)的持久層類注入到這個(gè)業(yè)務(wù)類中。
這里在增加用戶對象的時(shí)候,給用戶設(shè)定標(biāo)識(shí)的時(shí)候,簡單的用了一個(gè)當(dāng)前時(shí)間的毫秒數(shù)作為標(biāo)識(shí)。實(shí)際開發(fā)的過程中,這個(gè)地方需要用一個(gè)保證全局唯一的機(jī)制來保證這個(gè)標(biāo)識(shí)不能重復(fù)。
對外服務(wù)層開發(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 用來聲明這是一個(gè) Http Rest 接口類。通過類上的 @RequestMapping 和方法上的 @RequestMapping組合形成每個(gè)接口的調(diào)用路由。方法上的 @RequestMapping 中的 method 屬性聲明了 http 調(diào)用的方法。 @RequestBody 注解自動(dòng)將 post 數(shù)據(jù)中的 json 對象轉(zhuǎn)成 POJO 對象。@PathVariable 將 http url 路徑中的數(shù)據(jù)自動(dòng)轉(zhuǎn)換成為服務(wù)方法的參數(shù)。
Http Rest 接口測試
測試通過 Apache commons的 HttpClient 來調(diào)用 Http Rest 服務(wù)。
Http Resst 調(diào)用輔助類
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ā)起一個(gè)http請求 * * @param url 要訪問的 http 的 url * @return 訪問 http 后得到的回應(yīng)文本 */ 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ā)起一個(gè) http 請求 * * @param url 要訪問的 http 的 url * @param data post 請求中的 data 數(shù)據(jù) * @return 訪問 http 后得到的回應(yīng)文本 */ 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ù)據(jù) * * @param rd java.io.Reader 對象 * @throws Exception 發(fā)生錯(cuò)誤時(shí)拋出異常 */ 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ù)據(jù) * * @param is 輸入流 * @throws Exception 發(fā)生錯(cuò)誤時(shí)拋出異常 */ private String parseInputStream(InputStream is) throws Exception { return parseReader(new BufferedReader(new InputStreamReader(is))); } }
這里主要是實(shí)現(xiàn)了用 GET 和 POST 方法調(diào)用 Http Rest 服務(wù)的方法。
測試用例
采用 JUnit 來執(zhí)行測試用例。為了實(shí)現(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 聲明了兩個(gè)測試用例,一個(gè)測試了用戶修改功能,一個(gè)測試了用戶模糊查詢功能。 @Before 聲明了在執(zhí)行每個(gè)測試用例之前要做的準(zhǔn)備工作。這里首先往數(shù)據(jù)庫中插入三條數(shù)據(jù),同時(shí)也測試了數(shù)據(jù)的增加功能、精確查詢的功能。@After 聲明了執(zhí)行每個(gè)測試用例后的清理工作。這里主要是將之前插入的數(shù)據(jù)給刪除了。這里同步測試了用戶刪除的功能。
后記
這里就展示了一個(gè)完整的 SpringBoot 使用 JDBC Templet 的完整樣例。如果有在 Spring 下使用 JDBC Templet 的經(jīng)歷,那么在 Spring 里面主要是減少了很多配置的工作。
本文涉及的代碼已經(jīng)上傳到 GitHUB 上,大家也可以通過本地下載
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
java實(shí)現(xiàn)發(fā)送短信驗(yàn)證碼
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)發(fā)送短信驗(yàn)證碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07java 數(shù)值類型分秒時(shí)間格式化的實(shí)例代碼
這篇文章主要介紹了java 數(shù)值類型分秒時(shí)間格式化的實(shí)例代碼的相關(guān)資料,將秒或分鐘的值轉(zhuǎn)換為xx天xx小時(shí)xx分鐘xx秒 如果 “xx” 為0 自動(dòng)缺省,需要的朋友可以參考下2017-07-07SpringBoot整合SSO(single sign on)單點(diǎn)登錄
這篇文章主要介紹了SpringBoot整合SSO(single sign on)單點(diǎn)登錄,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06Springboot結(jié)合rabbitmq實(shí)現(xiàn)的死信隊(duì)列
為了保證訂單業(yè)務(wù)的消息數(shù)據(jù)不丟失,需要使用到RabbitMQ的死信隊(duì)列機(jī)制,本文主要介紹了Springboot結(jié)合rabbitmq實(shí)現(xiàn)的死信隊(duì)列,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09Java HashMap三種循環(huán)遍歷方式及其性能對比實(shí)例分析
這篇文章主要介紹了Java HashMap三種循環(huán)遍歷方式及其性能對比,結(jié)合具體實(shí)例形式分析了Java HashMap三種循環(huán)遍歷方式的實(shí)現(xiàn)方法、運(yùn)行效率及性能優(yōu)劣,需要的朋友可以參考下2019-10-10Java實(shí)現(xiàn)的文件過濾代碼分享(按后輟過濾)
這篇文章主要介紹了Java實(shí)現(xiàn)的文件過濾代碼分享,本文通過后輟名過濾,代碼寫簡潔,容易看懂,需要的朋友可以參考下2014-07-07