MyBatis 簡介
MyBatis 是一款優秀的持久層框架,它支持自定義 SQL、存盤程序以及高級映射,MyBatis 免除了幾乎所有的 JDBC 代碼以及設定引數和獲取結果集的作業,MyBatis 可以通過簡單的 XML 或注解來配置和映射原始型別、介面和 Java POJO(Plain Ordinary Java Objects,簡單 Java 物件)為資料庫中的記錄,
參考自 MyBatis 的官方簡介,
MyBatis 作為一款優秀的持久層框架,具有如下優點:
-
小巧并且簡單易學,
-
相比于 JDBC 減少了大量冗余的代碼,
-
將 SQL 陳述句與程式代碼進行分離,降低了耦合,便于管理,
-
提供 XML 標簽,支持撰寫動態 SQL 陳述句,
-
提供映射標簽,支持 Java 物件的屬性與資料表欄位的映射關系,
MyBatis 實踐
下面我們創建一個 Spring Boot 專案,整合 MyBatis,實作簡單的 CRUD 功能,
1. 引入依賴
POM 檔案如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springboot-mybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-mybatis</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. 配置 MySQL 和 MyBatis
組態檔 application.yml 的內容如下:
# 配置 MySQL
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# 配置 MyBatis
mybatis:
mapper-locations: classpath:mapper/*
type-aliases-package: com.example.entity
configuration:
map-underscore-to-camel-case: true
MyBatis 的配置項中:
-
mapper-locations:用來指定 mapper.xml 檔案的路徑,該檔案用于撰寫 SQL 陳述句, -
type-aliases-package:用來設定別名,它的作用是告訴 MyBatis 需要設定別名的物體類的所在的包,默認情況下,MyBatis 會使用物體類的非限定類名來作為它的別名,如將com.example.entity.User的別名設定為User或user(別名不區分大小寫),當然,MyBatis 也支持自定義別名,這個我們在后文中再聊, -
map-underscore-to-camel-case:用來開啟駝峰命名自動映射,如將資料表中的欄位 user_name 映射到物體物件的屬性 userName,
3. 物體類
撰寫簡單的 User 類:
package com.example.entity;
import lombok.Data;
import java.util.Date;
/**
* @Author john
* @Date 2021/11/14
*/
@Data
public class User {
private long id;
private String userName;
private int age;
private String address;
private Date createTime;
private Date updateTime;
}
User 類中封裝了用戶的 id、姓名、年齡、地址、創建時間以及修改時間等資訊,
4. 創建 user 表
user 表的欄位設計如下:

5. 撰寫 Mapper 介面和 mapper 檔案
首先撰寫 UserMapper 介面:
package com.example.mapper;
import com.example.entity.User;
/**
* @Author john
* @Date 2021/11/16
*/
public interface UserMapper {
void insertUser(User user);
User findUserById(long id);
}
介面中定義了兩個方法,insertUser 用來向資料表中插入一條記錄,findUserById 用來通過 id 查詢 User,
上述操作完成后,我們在 resources 檔案夾中創建 mapper/user-mapper.xml 檔案(檔案路徑在組態檔 application.yml 中設定),user-mapper.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.example.mapper.UserMapper">
<sql id="insertFields">
user_name, age, address, gmt_create, gmt_modified
</sql>
<sql id="selectFields">
id, user_name, age, address, gmt_create, gmt_modified
</sql>
<resultMap id="UserMap" type="User">
<result column="id" jdbcType="INTEGER" property="id"/>
<result column="user_name" jdbcType="VARCHAR" property="userName"/>
<result column="age" jdbcType="INTEGER" property="age"/>
<result column="address" jdbcType="VARCHAR" property="address"/>
<result column="gmt_create" jdbcType="DATE" property="createTime" />
<result column="gmt_modified" jdbcType="DATE" property="updateTime" />
</resultMap>
<select id="findUserById" parameterType="Long" resultMap="UserMap">
select
<include refid="selectFields"/>
from user
where id = #{id}
</select>
<insert id="insertUser" parameterType="User" keyProperty="id">
insert into user (<include refid="insertFields"/>)
values(#{userName}, #{age}, #{address}, UTC_TIMESTAMP(), UTC_TIMESTAMP())
</insert>
</mapper>
可以看到,Mapper 介面中定義的是 CRUD 相關的方法,mapper.xml 檔案中定義的是具體的 SQL 陳述句,MyBatis 允許我們將 Mapper 介面與 mapper.xml 檔案關聯在一起,這樣當呼叫 Mapper 介面中的方法時,實際的處理邏輯為執行 mapper.xml 檔案中對應的 SQL 陳述句,關聯 Mapper 介面和 mapper.xml 檔案時需要保證:
-
Mapper 介面的全限定名對應 mapper.xml 檔案的 namespace 值,
-
Mapper 介面的方法名對應 statement(每一個 SQL 就是一個 statement)的 id 值,
-
Mapper 介面中方法接收的引數對應 statement 的入參,
-
Mapper 介面中方法的回傳值對應 statement 的出參,
下面介紹一下 mapper.xml 檔案中幾個重要標簽的含義:
-
<sql>標簽:用于定義復用的 SQL 片段,如果多個 SQL 需要操作相同的欄位集,那么就可以使用<sql>標簽將這些欄位提取出來,然后在 SQL 陳述句中直接參考即可,參考的語法為<include refid=" "/>,其中 refid 的值就是<sql>的 id 值, -
<resultMap>標簽:用于創建資料表欄位與物體屬性的映射關系,在查詢操作中,MyBatis 會根據查詢到的欄位名找到 POJO 對應的屬性名,然后呼叫該屬性的 setter 方法進行賦值,如果資料表的欄位名與物體類的屬性名完全相同,或者符合駝峰式命名映射的規則,那么 MyBatis 可以直接完成賦值操作,否則的話,就需要我們使用<resultMap>標簽創建自定義的映射規則,告訴 MyBatis 欄位和屬性之間應該如何映射,本實驗中,user 表的 id 會自動映射為 User 物件的 id,user 表的 user_name 也會自動映射為 User 物件的 userName,但是 gmt_create 和 gmt_modified 不會映射為 createTime 和 updateTime,因為欄位名和屬性名既不完全一致,也不符合駝峰式命名映射的規則,所以這里我們需要使用<resultMap>來創建新的映射關系,其中屬性 id 用于指明該 resultMap 的標志,屬性 type 用于指明映射的物體類, -
<select>標簽:用于執行查詢操作, -
<insert>標簽:用于執行插入操作,
實際上,MyBatis 賦值時不一定會呼叫物體類屬性的 setter 方法,因為我們在編碼時可能并沒有添加該方法,以 User 類的屬性 id 為例,如果我們添加了 setId 方法,那么 MyBatis 會通過反射獲取到 setId 對應的 MethodInvoker,然后呼叫 setId 方法為 id 賦值;如果未設定 setId 方法,那么 MyBatis 會獲取屬性 id 對應的 SetFieldInvoker,然后為屬性賦值,詳見 MetaObject 類的 setValue 方法,
接下來介紹 SQL 陳述句中幾個重要屬性的含義:
-
parameterType:用于指定 SQL 陳述句的入參型別(可以是基本資料型別或者 JavaBean),該型別需要與對應的介面方法的入參型別一致,如果我們設定了別名,那么也可以使用別名作為引數,例如使用
User或user代替com.example.entity.User, -
resultMap:用于指定 SQL 陳述句的出參型別,以 insertUser 方法為例,在 Mapper 介面中,該方法的回傳值為 User 型別,所以對應的 SQL 陳述句的回傳值也應為 User 型別,由于 User 物件需要使用
<resultMap>進行屬性映射,所以我們將自定義的UserMap來作為 SQL 陳述句的回傳值型別, -
keyProperty:用于指定主鍵在 POJO 中對應的屬性名,需要配合資料庫的自增主鍵來使用,以 user 表為例,我們在建表的時候將表的主鍵 id 設定為了資料庫自增 id,因此在將 User 物件持久化到資料庫之前不需要為屬性 id 設定初始值,MySQL 會自動幫我們賦值,keyProperty 的作用就是告訴 MyBatis 哪個屬性是主鍵,
除了 resultMap 外,resultType 屬性也可用于指定出參類型,如果我們將 user 表中的欄位 gmt_create 和 gmt_modified 分別改為 create_time 和 update_time,那么就不需要使用 <resultMap> 標簽來配置映射規則,因為 user 表的所有欄位都可以和 User 物件的屬性一一對應,這樣在 SQL 陳述句中,就可以將 resultMap="UserMap" 替換為 resulType="User" 或 resulType="user",另外,在本實驗中,resultMap 標簽也可以定義為:
<resultMap id="UserMap" type="User">
<result column="gmt_create" jdbcType="DATE" property="createTime" />
<result column="gmt_modified" jdbcType="DATE" property="updateTime" />
</resultMap>
因為其他欄位會自動映射,不需要額外書寫,
6. 撰寫 Service
創建 UserService:
package com.example.service;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @Author john
* @Date 2021/11/16
*/
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public void insertUser(User user) {
userMapper.insertUser(user);
}
public User findUserById(long id) {
return userMapper.findUserById(id);
}
}
在 UserService 中注入 UserMapper 物件,并呼叫相關方法來添加/查詢 User,
為了能夠正常注入 UserMapper 物件,我們還需要再啟動類上添加 @MapperScan 注解,并指定 Mapper 介面所在的包:
package com.example;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.mapper")
public class SpringbootMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootMybatisApplication.class, args);
}
}
com.example.mapper 包下的所有 Mapper 介面都會被 Spring 掃描,
除了在啟動類上添加 @MapperScan 注解外,還可以在 Mapper 介面上直接添加 @Mapper 注解,這種方法相對比較麻煩,因為實際中我們可能會有多個 Mapper 介面,這樣就需要添加多個注解,
7. 測驗
撰寫測驗介面:
package com.example;
import com.example.entity.User;
import com.example.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringbootMybatisApplicationTests {
@Autowired
private UserService service;
@Test
public void addUser(){
User user = new User();
user.setUserName("John");
user.setAge(24);
user.setAddress("BUPT");
service.insertUser(user);
}
@Test
public void findUser(){
System.out.println(service.findUserById(1));
}
}
首先執行 addUser() 方法,執行成功后查詢資料表,得到如下資訊:

然后執行 findUser() 方法,執行結果如下:

至此,SpringBoot 整合 MyBatis 測驗成功!
MyBatis 設定別名的方式
方式一:在組態檔 application.yml 中添加配置,
yml 檔案的配置內容如下:
mybatis:
type-aliases-package: com.example.entity
本實驗采用此種方式設定別名,默認情況下物體類的別名為其類名,嚴格來說是首字母小寫的非限定類名,由于別名不區分大小寫,所以 User、user、uSer 的效果都是相同的,
MyBatis 也支持自定義別名,我們只需要在物體類上添加 @Alias 注解,就可以為其設定別名:
package com.example.entity;
import lombok.Data;
import org.apache.ibatis.type.Alias;
import java.util.Date;
/**
* @Author john
* @Date 2021/11/14
*/
@Data
@Alias("hello")
public class User {
private long id;
private String userName;
private int age;
private String address;
private Date createTime;
private Date updateTime;
}
上述代碼中,我們將 User 類的別名設定為了 hello,注意,若要使 @Alias 注解生效,必須配置 type-aliases-package 來指定物體類的包路徑,另外,@Alias 會使默認的別名變得無效,例如在本實驗中,User 類的別名只能是 hello,而不能是 User 或 user 等,
方式二:使用 MyBatis 的組態檔 filename.xml,
首先在 yml 檔案中設定 MyBatis 組態檔 filename.xml(filename 是組態檔的名稱)的路徑:
# 配置MyBatis
mybatis:
mapper-locations: classpath:mapper/*
config-location: classpath:mybatis/mybatis-config.xml #MyBatis組態檔
然后在 resource 檔案夾下創建 MyBatis 的組態檔 mapper/mybatis-config.xml(路徑和檔案名在 config-location 中設定),組態檔內容如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="https://www.cnblogs.com/johnlearning/p/true"/>
</settings>
<typeAliases>
<package name="com.example.entity"/>
</typeAliases>
</configuration>
幾個重要標簽的含義為:
-
<setting>標簽:用于開啟駝峰命名映射,其效果與在 yml 檔案中配置map-underscore-to-camel-case: true是相同的, -
<typeAliases>標簽:用于配置別名,子標簽<package>可以讓 MyBatis 掃描指定包下的物體類,其效果與在 yml 檔案中配置type-aliases-package: com.example.entity是相同的,
在方式一中,我們可以使用 @Alias 注解自定義別名,而在方式二中,我們可以通過<typeAliases> 的子標簽 <typeAlias> 來設定別名:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="https://www.cnblogs.com/johnlearning/p/true"/>
</settings>
<typeAliases>
<typeAlias type="com.example.entity.User" alias="hello"/>
</typeAliases>
</configuration>
<typeAlias> 標簽不需要配置 type-aliases-package 就可以生效,且該標簽與 <package> 標簽并不沖突,也就是說如果我們添加了 <package name="com.example.entity"/>,那么 User 類的別名既可以是 hello,也可以是 User 或 user 等,當然,方式二中也可以添加 @Alias 注解,但添加了該注解后,User 類的別名只能為 hello 或 @Alias 注解指定的別名,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/473397.html
標籤:Java
