SpringBoot整合Mybatis超詳細流程
前言
MyBatis 本是apache的一個開源專案iBatis, 2010年這個專案由apache software foundation 遷移到了google code,並且改名為MyBatis 。2013年11月遷移到Github。
MyBatis 是一款優秀的持久層框架,它支援自定義 SQL、儲存過程以及高階對映。MyBatis 免除了幾乎所有的 JDBC 程式碼以及設定引數和獲取結果集的工作。
MyBatis 可以通過簡單的 XML 或註解來配置和對映原始型別、介面和 Java POJO(Plain Ordinary Java Object,普通老式 Java 物件)為資料庫中的記錄。
因為 Mybatis的效能非常不錯,SpringBoot 官方推薦使用 Mybatis 來連線資料庫進行 CRUD 操作。
Mybatis的官方文件地址:https://mybatis.org/mybatis-3/zh/index.html
詳細流程
我們使用 IDEA 建立一個 SpringBoot 專案
初始化元件部分選擇 Web、JDBC API、MyBatis Framework、MySQL Driver
專案初始化完成之後,可以在 pom.xml
檔案中看到如下依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2.建立程式目錄
我們在 com.example 目錄下新建四個目錄,分別是 controller、dao、entity、service。
controller層負責具體的業務模組流程的控制
entity層用於存放我們的實體類,與資料庫中的屬性值基本保持一致,實現set和get的方法
dao層主要是做資料持久層的工作,負責與資料庫聯絡,封裝了增刪改查基本操作
service層主要負責業務模組的邏輯應用設計,具體要呼叫到已定義的DAO層的介面
然後在 resource 目錄下新建 mapper 目錄。這個 mapper 目錄是用來存放 SQL 語句的地方。
順便提一下,我們知道的 MVC 框架,即 model-view-controller 三層架構。這裡 model層=entity層,與資料庫的資料表對應,view層和 controller層結合非常緊密,需要聯合起來一起開發。可以簡單理解為 view層是做前端介面的展示,controller層做業務模流程塊的控制。
如果在網上看到有 mapper層這個概念,就記住,mapper層=dao層,就是對資料庫進行資料持久化操作。
不管是什麼框架,我們很多時候都會與資料庫進行互動。如果遇到一個場景我們都要去寫SQL語句,那麼我們的程式碼就會很冗餘。所以,我們就想到了把資料庫封裝一下,讓我們的資料庫的交道看起來像和一個物件打交道,這個物件通常就是DAO。當我們操作這個物件的時候,這個物件會自動產生SQL語句來和資料庫進行互動,我們就只需要使用DAO就行了。
通常我們在DAO層裡面寫介面,裡面有與資料打交道的方法。SQL語句通常寫在mapper檔案裡面的。
Service層是建立在DAO層之上的,建立了DAO層後才可以建立Service層,而Service層又是在Controller層之下的,因而Service層應該既呼叫DAO層的介面,又要提供介面給Controller層的類來進行呼叫,它剛好處於一箇中間層的位置。每個模型都有一個Service介面,每個介面分別封裝各自的業務處理方法。
3.理解後臺訪問流程
使用者從頁面前端,也就是我們所說的 view 層進行查詢訪問,進入到 controller 層找到對應的介面,接 著 controller 進行對 service 層進行業務功能的呼叫,service 要進入 dao 層查詢資料,dao 層呼叫 mapper.xml 檔案生成 sql 語句到資料庫中進行查詢。
在資料庫中查詢到資料,dao 層拿到實體物件的資料,接著交付給 service 層,接著 service 進行業務 邏輯的處理,返回結果給 controller,controller 根據結果進行最後一步的處理,返回結果給前端頁 面。
建立一個訪問使用者資訊的流程為:entity->dao->mapper->service->controller,這裡 mapper 指的是存放 SQL 語句的 xml 檔案。
4.核心檔案配置
這裡我們可以使用 application.properties 檔案,也可以使用 application.yml 檔案來進行配置,當然推薦使用 application.yml 檔案。
如果用 application.yml 在第一次啟動專案的時候報錯,專案右側 maven -> lifecycle -> clean一下即可。
server:
port: 8080
servlet:
context-path: /
spring:
datasource:
url: jdbc:mysql://localhost:3306/reserver?useUnicode=true & characterEncoding=utf-8 &
useSSL=true & serverTimezone=Asia/Shanghai
username: root
password: 666888
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:/static/mapper/*.xml
type-aliases-package: com.example.springboot.pojo
這裡注意 com.mysql.jdbc.Driver 和 com.mysql.cj.jdbc.Driver。前者是 mysql-connector-java 5 中的,後者是 mysql-connector-java 6 中的(需要設定時區),相當於說一個是舊版,一個是新版。我們可以到 pom.xml 檔案中檢視 mysql 驅動版本,而現在基本都是 6 以上的新版本,所以直接使用後者即可。
特別強調一點,連線MySQL時使用的是spring.datasource.username,不要順手打成spring.datasource.data-username,這個教訓太深刻了。
引數解讀:
driver-class-name:mysql驅動
url:mysql連線的url,預設是3306埠,zzz是資料庫名,useSSL是使用安全套階層連線進行資料傳輸(如果true出錯可以選擇false),serverTimezone設定時區,亞洲時區請設定上海或者香港,不要設定北京,因為系統裡沒有這個時區。
username 是使用者名稱,password 是密碼
mybatis.mapper-locations:用於將配置路徑下的 * .xml 檔案載入到 mybatis 中
# 方法一:只有一個路徑
mybatis.mapper-locations= classpath:mapper/*.xml
# 方法二:有多個路徑
mybatis.mapper-locations= classpath:mapper/*.xml,classpath:mapper/user/*.xml
- type-aliases-package:指定POJO掃描包來讓 mapper.xml 檔案的 resultType 自動掃描到自定義POJO,這樣就不用每次指定完全限定名
# mapper.xml檔案中設定
# 完全限定名
<select id="getUsers" resultType="com.example.entity.User">
# 指定了POJO掃描包之後
<select id="getUsers" resultType="User">
5.編寫entity
我們在編寫entity時遵循POJO的思想。
這裡需要提及“POJO最小侵入性程式設計”的概念,POJO(Plain Ordinary Java Object)意思是普通Java物件。類的成員是私有的,且有一系列的 setter and getter方法來提供訪問。
POJO的內在含義是指那些沒有從任何類繼承、也沒有實現任何介面,更沒有被其它框架侵入的java物件。POJO的格式是用於資料的臨時傳遞,它只能裝載資料,作為資料儲存的載體,而不具有業務邏輯處理的能力。
一般來講,是 entity 中要取的資料應該和資料表相對應,但不一定要全部取出。
我們在剛才建立的 entity 目錄中新建 User 類,定義屬性 id、username、age。
public class Student {
private String sId;
private String sName;
private String sBirth;
private String sSex;
public String getsId() {
return sId;
}
public void setsId(String sId) {
this.sId = sId ;
}
public String getsName() {
return sName;
}
public void setsName(String sName) {
this.sName = sName == null ? null : sName.trim();
}
public String getsBirth() {
return sBirth;
}
public void setsBirth(String sBirth) {
this.sBirth = sBirth == null ? null : sBirth.trim();
}
public String getsSex() {
return sSex;
}
public void setsSex(String sSex) {
this.sSex = sSex == null ? null : sSex.trim();
}
}
6.編寫dao
springboot 整合 mybatis 開發有兩種版本,註解版和配置檔案版。
註解版不需要配置任何檔案,拿來即用,主要依靠的是註解來生成 sql 語句。配置檔案版與註解版相比,僅僅稍微複雜一點,兩者的區別僅為mapper層處理的處理方式不一樣。配置檔案版多了一個xml檔案,但是配置更加靈活,邏輯結構更加清晰,可讀性更強。
註解版,用 @Mapper 註解標識,我們使用#{id}來標識引數。@Mapper 註解把 mapper 這個 DAO 交給 Spring 管理,不再寫 mapper 對映檔案
@Mapper
public interface UserDao {
@Select("select * from user where id=#{id}")
public User getUserById(int id);
@Delete("delete from user where id=#{id}")
public int deleteUserById(int id);
}
配置檔案版,需要給編寫的 dao 增加註解 @Repository。
@Repository註解修飾哪個類,則表明這個類具有對物件進行CRUD(增刪改查)的功能。
而且@Repository是@Component註解的一個派生品,所以被@Repository註解的類可以自動的被@ComponentScan 通過路徑掃描給找到。因此@Repository註解的類也能@Autowired實現自動裝配。
通常將dao介面注入到service層的時候,需要寫@Resource這個註解。加上@Repository,就是springboot生成一個bean,自動注入service的相關引用中。
我們在 dao 目錄中新建 UserDao 介面,定義好方法。
/*
實現兩個功能
1、根據使用者id查詢使用者資訊
2、查詢同一年齡下的所有使用者
返回一組資料我們用 List<E> 來儲存,傳遞多個引數我們用 Map 來儲存
例如 public List<User> selectById4(@Param("map") Map map);
*/
@Repository
public interface UserDao {
//不使用@Param
public User getUserById(Integer id);
//使用@Param
public User getUserById(@Param("id") int id);
public List<User> getUserByAge(@Param("age") int age);
}
我們推薦使用 @Param 進行傳參,當對映器方法需要多個引數時,這個註解可以被用於:給對映器方法中的每個引數來取一個名字。這裡有兩點好處:
在 xml 檔案中不需要再指定引數型別 parameterType
當傳遞物件時,使用 #{物件.屬性} 可以更清晰地提示自己
如果不使用 @Param,多引數將會以它們的順序位置和SQL語句中的表示式進行對映,這是預設的。
dao 層定義了介面,不需要寫具體的實現類,我們只需要在 mapper 中將檔案路徑對映好就行了。DAO的實現原理:它是通過JDK動態代理方式實現的,我們在啟動載入配置檔案的時候,它會根據 mapper 的 xml檔案去生成一個DAO的實現。
使用配置檔案版時,我們還需要在主程式中通過使用@MapperScan可以指定要掃描的Mapper類的包的路徑。
@MapperScan是要spring啟動時,掃描到所有的Mapper檔案,並生成代理類交給spring容器管理;
對著 dao 目錄點選滑鼠右鍵,選擇 copy reference 即可複製包路徑,貼上進 MapperScan 中即可。
@MapperScan("com.example.dao")
@SpringBootApplication
public class SpringmybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringmybatisApplication.class, args);
}
}
7.編寫Mapper
在 mapper 目錄下新建 UserMapper.xml 檔案。
mapper.xml 的檔案頭資訊我們一般不會去記憶,都是直接從官網給出的教程中複製 xml 的頭資訊,網址是:https://mybatis.org/mybatis-3/zh/getting-started.html
我們需要更改名稱空間 namespace 使之對應我們編寫的 DAO,SQL語句都寫在 mapper 標籤裡面。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dao.UserDao">
</mapper>
然後我們根據 UserDao 中要寫的方法進行配置,為了方便展示,我們這裡僅做查詢,現在 UserDao 中有兩個查詢方法。
查詢的話我們用 select 標籤,id 指定為方法名,resultType指明返回型別,標籤中間寫 SQL 語句。因為我們已經配置了type-aliases-package,直接寫 User 即可。
<select id="getUserById" resultType="User">
select * from `user` where id=#{id}
</select>
<select id="getUserById2" resultType="User">
select * from `user` where age=#{age}
</select>
我們在前面第四步核心檔案配置的時候指定了 POJO 掃描包,所以這裡 resultType 不需要完全限定名。
這裡 user 表完全可以不寫反引號,寫反引號主要是為了方便我們區分,這是資料庫的一個表。
編寫 Mapper.xml 檔案主要注意三點:
namespace相對應
id相對應
resultType相對應
目前我們所講的 resultType 返回單一型別的值,包括基礎型別 String、Integer、Long,還有定義好的 Class 物件。
resultMap 則可以返回多個型別的值,適合多表連線查詢。resultMap 的具體用法可以去官方文件中學習,這裡我們不做過多的瞭解。
8.編寫Service
我們需要在實現類中使用 @Service 註解,才能被 SpringBoot 掃描,在 Controller 中使用 @Autowired 注入
在 service 目錄中新建 UserService 類
//這裡只使用 @Service 也可以,括號裡的內容不影響
@Service("UserService")
public class UserService {
}
使用 @Autowired 註解自動裝配 UserDao。呼叫 dao 層介面設計邏輯應用
@Service("UserService")
public class UserService {
@Autowired
private UserDao userDao;
public User queryUser(int id){
return userDao.getUserById(id);
}
public List<User> queryUser2(int age){
return userDao.getUserByAge(age);
}
}
/*傳遞多個引數我們可以用 Map 來實現
public List<User> queryUser4(Integer age, Integer start, Integer move){
Map<String,Object> hashMap=new HashMap<>();
hashMap.put("age",age);
hashMap.put("start",start);
hashMap.put("move",move);
return userDao.selectById4(hashMap);
}
*/
9.編寫Controller
在 controller 目錄中新建 UserController 類
這裡我們使用 Restful 風格,直接返回資料。
使用 @Autowired 註解自動裝配 UserService。編寫介面為 UserService 傳輸資料
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/getUser")
public User getUser(@RequestParam("id") int id){
return userService.queryUser(id);
}
@GetMapping("/getUser2")
public List<User> getUser2(@RequestParam("age") int age){
return userService.queryUser2(age);
}
}
10.執行專案
執行 SpringBoot 專案,我們在瀏覽器的位址列中輸入:
localhost:8081/getUser?id=1
localhost:8081/getUser2?age=20
即可看到返回了 id=1 和 age=20 的使用者的 JSON 資料。因為這裡是直接在位址列輸入引數和值,是採用 get 方式傳輸的,所以必須使用 GetMapping。
到這一步,整個的後臺訪問流程就全部打通了,大家仔細理解其中的邏輯,多多揣摩。
參考文章
Mybatis官方文件
Springboot與MyBatis簡單整合
spring boot框架mybatis.mapper-locations配置問題詳解
MySQL驅動和時區設定
SpringBoot整合Mybatis完整詳細版
mybatis返回值型別及正確使用resultType和resultMap
Mybatis實現資料持久化的三種方式