我是小先,一個專注大數據、分布式技術的非斜槓青年,愛Coding,愛閱讀、愛攝影,更愛生活!
博客主頁:https://me.csdn.net/u010974701
原始碼倉庫:https://github.com/zhshuixian/learn-spring-boot-2
考慮到 MyBatis 應用比較廣泛,這裡將會使用 MyBatis 作為主要的 Java 持久層框架,對 MyBatis Plus 感興趣的讀者可以對照本小節內容,參考其官網 https://mybatis.plus/ 和其 Spring Boot 啟動器 mybatis-plus-boot-starter。這一小節將以用戶信息表的為例子實戰 MyBatis 連接 SQL 資料庫並讀寫數據,主要分為如下幾個部分:
MyBatis 的依賴引入
MyBatis 連接 MySQL
MyBatis 實體類
MyBatis 寫入、更新、刪除、查詢數據
MyBatis 多筆查詢、分頁查詢
MyBatis 使用 Mapper.xml 方式
這裡使用 MySQL,如果你想使用如:PostgreSQL 等其他的資料庫,只需要更改相對應的依賴和指定 Driver 驅動包即可。這裡需要你提前安裝好 MySQL 或其他 SQL 資料庫。
參考文章在 Linux 下安裝 MySQL 8 : https://blog.csdn.net/u010974701/article/details/85625228
安裝完成後運行如下命令:
1create database spring;
MyBatis 官網:https://mybatis.org/mybatis-3/zh/index.html
MyBatis 是一款優秀的持久層框架,它支持定製化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可以使用簡單的 XML 或註解來配置和映射原生類型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 對象)為資料庫中的記錄。
相對於 Spring Data JPA 差不多可以不用寫 SQL 的框架而言,MyBatis 在於開發者可以靈活的編寫 SQL,但帶來的麻煩就是項目中一堆 Mapper.xml 等一堆配置文件。即使通過 MyBatis 的代碼生成器,自動生成實體類、相關配置文件減少了開發者的工作,但有時更改一個表欄位,帶來的結果可能是需要同時修改好幾個 XML 和 Java 代碼,使得開發者在 xml 的配置文件和 Java 代碼之間經常切換。
後來,MyBatis 做了大量的升級優化,可以通過使用註解來減少相關的配置文件。在開篇介紹《什麼是 Spring Boot》中提到,Spring Boot 一大特色就是自動配置(AutoConfiguration),為許多第三方開發庫提供了幾乎可以零配置的開箱即用的能力,如 MyBatis。而 MyBatis 開箱即用的啟動器(Starter) 即 mybatis-spring-boot-starter,使得 Spring Boot 整合 MyBatis,可以做到幾乎 0 配置開發。mybatis-spring-boot-starter 支持傳統的 Mapper.xml 的配置方法;支持幾乎沒有配置的註解方式。
本小節主要使用註解的方式,Mapper.xml 方式也會介紹。
MyBatis integration with Spring Boot 官方 GitHub 倉庫 https://github.com/mybatis/spring-boot-starter
MyBatis Spring-Boot-Starter will help you use MyBatis with Spring Boot。
2、MyBatis 的配置新建項目 03-sql-mybatis,記得勾選 MyBatis 、MySQL 依賴,注意 Spring Boot 的版本要為 2.1.X 版本。
MyBatis 對 Spring Boot 版本支持
master(2.1.x) : MyBatis 3.5+, MyBatis-Spring 2.0+(2.0.3+ recommended), Java 8+ and Spring Boot 2.1+
2.0.x : MyBatis 3.5+, MyBatis-Spring 2.0+, Java 8+ and Spring Boot 2.0/2.1.
1.3.x : MyBatis 3.4+, MyBatis-Spring 1.3+, Java 6+ and Spring Boot 1.5
對於 MyBatis 的分頁,在本小節中,通過 Pagehelper 來實現。
Gradle 依賴
1dependencies {
2 implementation 'org.springframework.boot:spring-boot-starter-web'
3 implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.1'
4 implementation 'com.github.pagehelper:pagehelper-spring-boot-starter:1.2.13'
5 compileOnly 'org.projectlombok:lombok'
6 runtimeOnly 'mysql:mysql-connector-java'
7 annotationProcessor 'org.projectlombok:lombok'
8 testImplementation('org.springframework.boot:spring-boot-starter-test') {
9 exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
10 }
11}
1 <dependencies>
2 <dependency>
3 <groupId>org.springframework.boot</groupId>
4 <artifactId>spring-boot-starter-web</artifactId>
5 </dependency>
6 <dependency>
7 <groupId>org.mybatis.spring.boot</groupId>
8 <artifactId>mybatis-spring-boot-starter</artifactId>
9 <version>2.1.1</version>
10 </dependency>
11 <dependency>
12 <groupId>mysql</groupId>
13 <artifactId>mysql-connector-java</artifactId>
14 <scope>runtime</scope>
15 </dependency>
16 <dependency>
17 <groupId>org.projectlombok</groupId>
18 <artifactId>lombok</artifactId>
19 <optional>true</optional>
20 </dependency>
21 <dependency>
22 <groupId>org.springframework.boot</groupId>
23 <artifactId>spring-boot-starter-test</artifactId>
24 <scope>test</scope>
25 <exclusions>
26 <exclusion>
27 <groupId>org.junit.vintage</groupId>
28 <artifactId>junit-vintage-engine</artifactId>
29 </exclusion>
30 </exclusions>
31 </dependency>
32 <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter -->
33 <dependency>
34 <groupId>com.github.pagehelper</groupId>
35 <artifactId>pagehelper-spring-boot-starter</artifactId>
36 <version>1.2.13</version>
37 </dependency>
38 </dependencies>
編輯 /src/main/resources/application.properties 文件,寫入如下內容,對於使用註解的方式來說,除此之外沒有其他配置了,至於 MyBatis 如何連接到資料庫,如何管理連接,Mapper 類如何跟表映射,這些統統交給 mybatis-spring-boot-starter:
1# 資料庫 URL、用戶名、密碼、JDBC Driver更換資料庫只需更改這些信息即可
2# MySQL 8 需要指定 serverTimezone 才能連接成功
3spring.datasource.url=jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
4spring.datasource.password=xiaoxian
5spring.datasource.username=root
6spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
7# MyBatis 駝峰命名轉換
8mybatis.configuration.map-underscore-to-camel-case=true
9# 指定 Mapper 文件的地址
10mybatis.mapper-locations=classpath:mapper/*.xml
11## pagehelper
12pagehelper.helperDialect=mysql
13pagehelper.reasonable=true
14pagehelper.supportMethodsArguments=true
15pagehelper.params=count=countSql
在 Spring Boot 啟動類 *Application 中,添加 @MapperScan("org.xian.boot.mapper"),自動掃描 org.xian.boot.mapper 下的 Mapper 類,使用此註解,無需再所有的 Mapper 類裡添加 @Mapper 註解
1@SpringBootApplication
2@MapperScan("org.xian.boot.mapper")
3public class BootApplication {
4 public static void main(String[] args) {
5 SpringApplication.run(BootApplication.class, args);
6 }
7}
MyResponse:通用消息返回類,增加、刪除、修改操作是否成功和信息返回的類:
1@Getter
2@Setter
3@NoArgsConstructor
4@AllArgsConstructor
5@ToString
6public class MyResponse implements Serializable {
7 private static final long serialVersionUID = -2L;
8 private String status;
9 private String message;
10}
項目依舊劃分為三層,只不過數據持久層框架換成了 MyBatis。
API 接口層:提供 RESTful API 接口,是系統對外的交互的接口。
接口服務層:應用的主要邏輯部分,不推薦在 API 接口層寫應用邏輯。
數據持久層:編寫相應的 MyBatis Mapper 接口,實現與 MySQL 資料庫的交互。
本小節中,將實現如下幾個 RESTful API 接口:
/api/user/insert : 插入一條數據/api/user/select : 查詢一條數據/api/user/update : 更新一條數據
/api/user/delete : 刪除一條數據
/api/user/selectAll : 瀏覽所有數據
/api/user/selectPage : 分頁瀏覽
3.1、數據表結構和 Mapper 實體類跟上一小節的表結構一樣:
欄位名欄位類型備註user_idbigint主鍵,自增usernamevarchar(18)用戶名,非空唯一nicknamevarchar(36)用戶暱稱,非空user_agetinyint用戶年齡user_sexvarchar(2)用戶性別SQL 語句
1-- MySQL
2create table sys_user
3(
4 user_id bigint auto_increment,
5 username varchar(18) not null,
6 nickname varchar(36) not null,
7 user_age tinyint null,
8 user_sex varchar(2) null,
9 constraint sys_user_pk
10 primary key (user_id)
11);
Mapper 實體類:新建 package,名稱為 entity 。在 entity下新建一個 SysUser 類:
1@Data
2public class SysUser implements Serializable {
3 private static final long serialVersionUID = 4522943071576672084L;
4
5 private Long userId;
6
7 @NotEmpty(message = "用戶名不能為空")
8 @Pattern(regexp = "^[a-zA-Z0-9]{3,16}$", message = "用戶名需3到16位的英文,數字")
9 private String username;
10
11 @NotEmpty(message = "用戶暱稱不能為空")
12 private String nickname;
13
14 @Range(min=0, max=100,message = "年齡需要在 0 到 100 之間")
15 private Integer userAge;
16
17 private String userSex;
18}
@NotEmpty(message = " "):不能為空,message 表示 null 或者字符長度為 0 時候的提示信息。
@Pattern:正則表達式,例如你可以用來驗證用戶名、密碼是否符合規範。
@Range:指定最大值和最小值,例如指定分數最大是 100。3.2、註解方式的 Mapper 接口新建 mapper 的包,新建 SysUserMapper 接口。跟 JPA 不同是,你需要通過註解或者 mapper.xml 的方式自定義編寫 SQL。OnXml 結尾的方法是使用 Mapper.xml 方式指定 SQL ,這在後面會提到,其和不帶 OnXml 後綴的方法是等同的。
1public interface SysUserMapper {
2 /** 往 sys_user 插入一條記錄
3 * @param sysUser 用戶信息
4 */
5 @Insert("Insert Into sys_user(username, nickname, user_age, user_sex) " +
6 "Values(#{username}, #{nickname}, #{userAge}, #{userSex})")
7 @Options(useGeneratedKeys = true, keyProperty = "userId")
8 void insert(SysUser sysUser);
9 void insertOnXml(SysUser sysUser);
10
11 /** 根據用戶 ID 查詢用戶信息
12 * @param userId 用戶 ID
13 * @return 用戶信息
14 */
15 @Select("Select user_id,username, nickname, user_age, user_sex From sys_user Where user_id=#{userId}")
16 @Results({
17 @Result(property = "userId", column = "user_id"),
18 @Result(property = "userAge", column = "user_age"),
19 @Result(property = "userSex", column = "user_sex")
20 })
21 SysUser selectByUserId(Long userId);
22 SysUser selectByUserIdOnXml(Long userId);
23
24 /** 根據用戶名更新用戶暱稱、用戶年齡、用戶性別 信息
25 * @param sysUser 用戶信息
26 */
27 @Update("Update sys_user Set nickname=#{nickname}, user_age=#{userAge}, user_sex=#{userSex} Where username=#{username}")
28 void update(SysUser sysUser);
29 void updateOnXml(SysUser sysUser);
30
31 /** 根據用戶 ID 刪除用戶信息
32 * @param userId 用戶 ID
33 */
34 @Delete("Delete From sys_user where user_id=#{userId}")
35 void delete(Long userId);
36 void deleteOnXml(Long userId);
37
38 /** 瀏覽所有用戶信息
39 * @return 所有用戶信息
40 */
41 @Select("Select * From sys_user")
42 List<SysUser> selectAll();
43 List<SysUser> selectAllOnXml();
44}
@Insert,@Select,@Update, @Delete 分別註解 SQL 的 insert,select,update,delete 語句。
MyBatis 的 SQL 傳入參數通過 #{param} 的方式,param 的名字應當和你 Java 變量名一樣。SQL 的其他部分和標準的 SQL 語句沒有區別。如果 Mapper 接口方法傳入的是一個類,也無需手動使用 Getter 方法給 SQL 的傳入參數賦值。MyBatis 會自動根據類中的成員變量名自動賦值。
@Results 如果沒有開啟 MyBatis 駝峰命名轉換,或者某些欄位不符合駝峰命名轉換規則,如:資料庫中欄位名稱為 user_sex,而 Java 類中的成員變量卻是 sex,則需要通過此方式手動進行映射。
@Result(property = "userId", column = "user_id"),property 指定 Java 類的成員變量名,column 指定資料庫的欄位名。
3.3、接口服務層 Service新增 service 的 Package 包,新增 SysUserService: 1@Service
2public class SysUserService {
3 @Resource
4 private SysUserMapper sysUserMapper;
5
6 /** 保存一條記錄
7 * @param sysUser 用戶信息
8 * @return 保存結果
9 */
10 public MyResponse insert(SysUser sysUser) {
11 try {
12 sysUserMapper.insert(sysUser);
13 return new MyResponse("success", "新增成功");
14 } catch (Exception e) {
15 return new MyResponse("error", e.getMessage());
16 }
17 }
18
19 /** 根據用戶 ID 查詢一條記錄
20 * @param userId 用戶 ID
21 * @return 用戶信息
22 */
23 public SysUser select(Long userId) {
24 return sysUserMapper.selectByUserIdOnXml(userId);
25 }
26
27 /** 根據用戶名更新用戶年齡、性別、暱稱信息
28 * @param sysUser 用戶信息
29 * @return 結果
30 */
31 public MyResponse update(SysUser sysUser) {
32 try {
33 sysUserMapper.update(sysUser);
34 return new MyResponse("success", "更新成功");
35 } catch (Exception e) {
36 return new MyResponse("error", e.getMessage());
37 }
38 }
39
40 /** 根據用戶 ID 刪除用戶信息
41 * @param userId 用戶 ID
42 * @return 操作結果
43 */
44 public MyResponse delete(Long userId) {
45 try {
46 sysUserMapper.delete(userId);
47 return new MyResponse("success", "刪除成功");
48 } catch (Exception e) {
49 return new MyResponse("error", e.getMessage());
50 }
51 }
52
53 /** 瀏覽所有用戶信息
54 * @return 所有用戶信息
55 */
56 public List<SysUser> selectAll() {
57 return sysUserMapper.selectAll();
58 }
59
60 /** 分頁瀏覽
61 * @return 一頁的用戶信息
62 */
63 public PageInfo<SysUser> selectPage(int page,int size) {
64 // PageHelper 隨後執行的查詢會自動分頁
65 PageHelper.startPage(page, size);
66 PageHelper.orderBy("user_id DESC");
67 return PageInfo.of(sysUserMapper.selectAllOnXml());
68 }
69}
@Service:定義一個 Bean ,此註解的類會自動註冊到 Spring 容器。
@Resource:相對於 @Autowired 註解,Bean 的自動裝配。
PageHelper.startPage(page, size); 調用此方法後,隨後的查詢講自動使用分頁模式。
PageInfo.of(sysUserMapper.selectAllOnXml()); 講查詢返回某一頁的信息使用 PageInfo 打包。
3.4、 API 接口層新增 controller 的 Package 包,新增 SysUserController
1@RestController
2@RequestMapping(value = "/api/user")
3public class SysUserController {
4 @Resource
5 private SysUserService sysUserService;
6
7 @PostMapping(value = "/insert")
8 public MyResponse insert(@RequestBody SysUser sysUser) {
9 return sysUserService.insert(sysUser);
10 }
11
12 @PostMapping(value = "select")
13 public SysUser select(@RequestBody Long userId) {
14 return sysUserService.select(userId);
15 }
16
17 @PostMapping(value = "/update")
18 public MyResponse update(@RequestBody SysUser sysUser) {
19 return sysUserService.update(sysUser);
20 }
21
22 @PostMapping(value = "delete")
23 public MyResponse delete(@RequestBody Long userId) {
24 return sysUserService.delete(userId);
25 }
26
27 @GetMapping("selectAll")
28 public List<SysUser> selectAll() {
29 return sysUserService.selectAll();
30 }
31
32 @GetMapping("selectPage")
33 public PageInfo<SysUser> selectPage(@RequestParam(defaultValue = "0") Integer page,
34 @RequestParam(defaultValue = "3") Integer size) {
35 return sysUserService.selectPage(page, size);
36 }
37}
運行項目,使用 Postman 訪問 RESTful API 接口:
/api/user/insert : 插入一條數據
/api/user/select : 查詢一條數據
/api/user/update : 更新一條數據
/api/user/delete : 刪除一條數據
/api/user/selectAll : 瀏覽所有數據
/api/user/selectPage : 分頁瀏覽
上文通過註解的方式指定 Mapper 接口的方式,而 Mapper.xml 自定義 SQL 的方式在 Spring Boot 中也做了極大的優化,你只需要在 resources/application.properties 指定 Mapper.xml 文件的位置,其他的配置將由 MyBatis 的啟動器(Starter)自動完成。
在 3.2 小節 Mapper 接口,每個使用註解自定義 SQL 的方法下面,有個 OnXml 後綴的方法,如果在 SysUserService 直接調用此方法會報錯。在使用這些方法前,我們還需要在 Mapper.xml 文件下自定義 SQL 欄位:
新建 resources/mapper/SysUserMapper.xml 文件:
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3<!-- 指定 Mapper 類 -->
4<mapper namespace="org.xian.boot.mapper.SysUserMapper">
5 <!-- 返回結果的欄位名、欄位類型,對應類的成員變量名 ,可以定義多個 id 值不同的 resultMap -->
6 <resultMap id="BaseResultMap" type="org.xian.boot.entity.SysUser">
7 <id column="user_id" jdbcType="BIGINT" property="userId"/>
8 <result column="username" jdbcType="VARCHAR" property="username"/>
9 <result column="nickname" jdbcType="VARCHAR" property="nickname"/>
10 <result column="user_age" jdbcType="TINYINT" property="userAge"/>
11 <result column="user_sex" jdbcType="VARCHAR" property="userSex"/>
12 </resultMap>
13 <!-- SQL 語句 的通用部分 -->
14 <sql id="SysColumn">
15 user_id, username, nickname, user_age, user_sex
16 </sql>
17 <!-- Id 為 Mapper 類的成員變量名 ,resultMap 指定返回接受類 -->
18 <select id="selectAllOnXml" resultMap="BaseResultMap">
19 select
20 <!-- 使用 Include 包含通用的 SQL 部分 -->
21 <include refid="SysColumn"/>
22 from sys_user
23 </select>
24
25 <select id="selectByUserIdOnXml" parameterType="java.lang.Long" resultMap="BaseResultMap">
26 select
27 <include refid="SysColumn"/>
28 from sys_user Where user_id=#{userId}
29 </select>
30 <!-- parameterType 指定傳入參數類型 -->
31 <insert id="insertOnXml" parameterType="org.xian.boot.entity.SysUser">
32 Insert Into sys_user(username, nickname, user_age, user_sex)
33 Values (#{username}, #{nickname}, #{userAge}, #{userSex})
34 </insert>
35 <!-- 完整代碼看原始碼倉庫 03-sql-mybatis 的 resources/mapper/SysUserMapper.xml -->
36</mapper>
在 Spring Boot 中整合 MyBatis,其啟動器 mybatis-spring-boot-starter 將許多配置自動完成,不管是使用註解方式還是 Mapper.xml 的方式,都變得非常簡潔。
另外,MyBatis Generator 支持自動生成 Mapper 接口、Mapper.xml、實體類,感興趣的讀者可以自行搜索了解。
下一小節中,將實戰 Spring Boot 2.X 整合 RocketMQ,對於 NoSQL 的部分將稍微延後。實戰 Spring Boot 2.X 的系列文章,主要分為如下幾個部分,更新完 RocketMQ 後,大概率會更新 Redis 緩存:
Spring Boot 2.X 實戰https://mybatis.org/mybatis-3/zh/index.html
https://github.com/mybatis/spring-boot-starter歡迎關注《編程技術進階》公眾號或者小先的 CSDN 博客(大數據小先)!