作者丨武哥
來源丨武哥聊編程
1. MyBatis 介紹
大家都知道,MyBatis 框架是一個持久層框架,是 Apache 下的頂級項目。Mybatis 可以讓開發者的主要精力放在 sql 上,通過 Mybatis 提供的映射方式,自由靈活的生成滿足需要的 sql 語句。使用簡單的 XML 或注解來配置和映射原生信息,將接口和 JAVA 的 POJOs 映射成數據庫中的記錄,在國內可謂是占據了半壁江山。本文主要通過兩種方式來對 Spring Boot 集成 MyBatis 做一講解。重點講解一下基于注解的方式。因為實際項目中使用注解的方式更多一點,更簡潔一點,省去了很多 xml 配置(這不是絕對的,有些項目組中可能也在使用 xml 的方式)。
2. MyBatis 的配置
2.1 依賴導入
Spring Boot 集成 MyBatis,需要導入 mybatis-spring-boot-starter 和 MySQL 的依賴,這里我們使用的版本時 1.3.2,如下:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
我們點開 mybatis-spring-boot-starter 依賴,可以看到我們之前使用 Spring 時候熟悉的依賴,就像我在課程的一開始介紹的那樣,Spring Boot 致力于簡化編碼,使用 starter 系列將相關依賴集成在一起,開發者不需要關注繁瑣的配置,非常方便。
<!-- 省去其他 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</dependency>
2.2 properties.yml配置
我們再來看一下,集成 MyBatis 時需要在 properties.yml 配置文件中做哪些基本配置呢?
# 服務端口號
server:
port: 8080
# 數據庫地址
datasource:
url: localhost:3306/blog_test
spring:
datasource: # 數據庫配置
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://${datasource.url}?useSSL=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true&failOverReadOnly=false&maxReconnects=10
username: root
password: 123456
hikari:
maximum-pool-size: 10 # 最大連接池數
max-lifetime: 1770000
mybatis:
# 指定別名設置的包為所有entity
type-aliases-package: com.itcodai.course10.entity
configuration:
map-underscore-to-camel-case: true # 駝峰命名規范
mApper-locations: # mapper映射文件位置
- classpath:mapper/*.xml
我們來簡單介紹一下上面的這些配置:關于數據庫的相關配置,我就不詳細的解說了,這點相信大家已經非常熟練了,配置一下用戶名、密碼、數據庫連接等等,這里使用的連接池是 Spring Boot 自帶的 hikari,感興趣的朋友可以去百度或者谷歌搜一搜,了解一下。
這里說明一下 map-underscore-to-camel-case: true, 用來開啟駝峰命名規范,這個比較好用,比如數據庫中字段名為:user_name, 那么在實體類中可以定義屬性為 userName (甚至可以寫成 username,也能映射上),會自動匹配到駝峰屬性,如果不這樣配置的話,針對字段名和屬性名不同的情況,會映射不到。
3. 基于 xml 的整合
使用原始的 xml 方式,需要新建 UserMapper.xml 文件,在上面的 application.yml 配置文件中,我們已經定義了 xml 文件的路徑:classpath:mapper/*.xml,所以我們在 resources 目錄下新建一個 mapper 文件夾,然后創建一個 UserMapper.xml 文件。
<?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.itcodai.course10.dao.UserMapper">
<resultMap id="BaseResultMap" type="com.itcodai.course10.entity.User">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="user_name" jdbcType="VARCHAR" property="username" />
<result column="password" jdbcType="VARCHAR" property="password" />
</resultMap>
<select id="getUserByName" resultType="User" parameterType="String">
select * from user where user_name = #{username}
</select>
</mapper>
這和整合 Spring 一樣的,namespace 中指定的是對應的 Mapper, <resultMap> 中指定對應的實體類,即 User。然后在內部指定表的字段和實體的屬性相對應即可。這里我們寫一個根據用戶名查詢用戶的 sql。
實體類中有 id,username 和 password,我不在這貼代碼,大家可以下載源碼查看。UserMapper.java 文件中寫一個接口即可:
User getUserByName(String username);
中間省略 service 的代碼,我們寫一個 Controller 來測試一下:
@RestController
public class TestController {
@Resource
private UserService userService;
@RequestMapping("/getUserByName/{name}")
public User getUserByName(@PathVariable String name) {
return userService.getUserByName(name);
}
}
啟動項目,在瀏覽器中輸入:http://localhost:8080/getUserByName/CSDN 即可查詢到數據庫表中用戶名為 CSDN 的用戶信息(事先搞兩個數據進去即可):
{"id":2,"username":"CSDN","password":"123456"}
這里需要注意一下:Spring Boot 如何知道這個 Mapper 呢?一種方法是在上面的 mapper 層對應的類上面添加 @Mapper 注解即可,但是這種方法有個弊端,當我們有很多個 mapper 時,那么每一個類上面都得添加 @Mapper 注解。另一種比較簡便的方法是在 Spring Boot 啟動類上添加@MaperScan 注解,來掃描一個包下的所有 mapper。如下:
@SpringBootApplication
@MapperScan("com.itcodai.course10.dao")
public class Course10Application {
public static void main(String[] args) {
SpringApplication.run(Course10Application.class, args);
}
}
這樣的話,com.itcodai.course10.dao 包下的所有 mapper 都會被掃描到了。
4. 基于注解的整合
基于注解的整合就不需要 xml 配置文件了,MyBatis 主要提供了 @Select, @Insert, @Update, Delete 四個注解。這四個注解是用的非常多的,也很簡單,注解后面跟上對應的 sql 語句即可,我們舉個例子:
@Select("select * from user where id = #{id}")
User getUser(Long id);
這跟 xml 文件中寫 sql 語句是一樣的,這樣就不需要 xml 文件了,但是有個問題,有人可能會問,如果是兩個參數呢?如果是兩個參數,我們需要使用 @Param 注解來指定每一個參數的對應關系,如下:
@Select("select * from user where id = #{id} and user_name=#{name}")
User getUserByIdAndName(@Param("id") Long id, @Param("name") String username);
可以看出,@Param 指定的參數應該要和 sql 中 #{} 取的參數名相同,不同則取不到??梢栽?controller 中自行測試一下,接口都在源碼中,文章中我就不貼測試代碼和結果了。
有個問題需要注意一下,一般我們在設計表字段后,都會根據自動生成工具生成實體類,這樣的話,基本上實體類是能和表字段對應上的,最起碼也是駝峰對應的,由于在上面配置文件中開啟了駝峰的配置,所以字段都是能對的上的。但是,萬一有對不上的呢?我們也有解決辦法,使用 @Results 注解來解決。
@Select("select * from user where id = #{id}")
@Results({
@Result(property = "username", column = "user_name"),
@Result(property = "password", column = "password")
})
User getUser(Long id);
@Results 中的 @Result 注解是用來指定每一個屬性和字段的對應關系,這樣的話就可以解決上面說的這個問題了。
當然了,我們也可以 xml 和注解相結合使用,目前我們實際的項目中也是采用混用的方式,因為有時候 xml 方便,有時候注解方便,比如就上面這個問題來說,如果我們定義了上面的這個 UserMapper.xml,那么我們完全可以使用 @ResultMap 注解來替代 @Results 注解,如下:
@Select("select * from user where id = #{id}")
@ResultMap("BaseResultMap")
User getUser(Long id);
@ResultMap 注解中的值從哪來呢?對應的是 UserMapper.xml 文件中定義的 <resultMap> 時對應的 id 值:
<resultMap id="BaseResultMap" type="com.itcodai.course10.entity.User">
這種 xml 和注解結合著使用的情況也很常見,而且也減少了大量的代碼,因為 xml 文件可以使用自動生成工具去生成,也不需要人為手動敲,所以這種使用方式也很常見。
5. 總結
本節主要系統的講解了 Spring Boot 集成 MyBatis 的過程,分為基于 xml 形式和基于注解的形式來講解,通過實際配置手把手講解了 Spring Boot 中 MyBatis 的使用方式,并針對注解方式,講解了常見的問題已經解決方式,有很強的實戰意義。在實際項目中,建議根據實際情況來確定使用哪種方式,一般 xml 和注解都在用。