SpringBoot 整合 Mybatis 實現數據表增刪改查,保姆級教程!
01、背景介紹
在上一篇文章中,我們介紹了利用 Spring Boot JPA 來實現對數據庫的訪問操作,雖然它在國外廣泛流行,但是在國內流行程度遠不如 MyBatis。
原因在于,在 ORM 框架中其實還有另一個翹楚,那就是剛剛說到的 MyBatis,它的實現方式與 Spring Boot JPA 完全不同,MyBatis 框架不會幫助用戶動態生成 SQL 語句,它把 SQL 的編寫工作完全交給了用戶,開發者可以像在本地數據庫中寫 SQL 語句一樣快速的完成對數據庫表的操作,非常易于新人上手,唯一的缺點就是配置工作量很大,好在有代碼生成器,可以幫助開發者減輕不少的開發工作量。
ORM 框架發展至今,只剩下兩家了,一個是以Hibernate為代表,開發者可以不用寫一句 SQL 就可以輕松完成對數據庫的訪問操作;另一個是以MyBatis為代表,開發者可以根據自己的業務需求靈活的編寫動態 SQL 完成對數據庫的訪問操作。
總的來說,兩者各有特點,如果當前業務所有的業務操作都是單表并且沒有很復雜的查詢要求,那么采用 Spring Boot JPA 來開發,效率會更高;如果業務很復雜,各表之間經常需要連表查詢,那么采用MyBatis來開發會是一個非常好的選擇。在企業級系統開發中,因為業務比較復雜,國內采用MyBatis來開發的項目相對比較多些。
今天這篇文章我們就具體來說說如何在 Spring Boot 中整合 MyBatis 完成數據庫表的增刪改查操作。
02、應用實踐
2.1、工程配置
首先,在pom.xml文件中引入mybatis-spring-boot-starter依賴,具體如下:
<!--spring boot mybatis支持-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<!--mysql 驅動-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
關于mybatis-spring-boot-starter與Spring Boot的版本對應關系,可以參考如下:
- 1.3.x版本:適用于 MyBatis 3.4+、Java 6+、Spring Boot 1.5
- 2.0.x版本:適用于 MyBatis 3.5+、Java 8+、Spring Boot 2.0/2.1
- 2.1.x版本:適用于 MyBatis 3.5+、Java 8+、Spring Boot 2.1+
本項目采用的是Spring Boot 2.1.0構建,因此選擇2.0.0版本。
然后,在application.properties文件中添加數據源信息和相關的MyBatis配置參數,內容如下:
# 數據源配置
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 打印SQL語句
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
MyBatis支持兩種開發模式。
- 第一種:基于注解的配置實現
- 第二種:基于XML的配置實現
下面我們一起來這兩種具體的應用方式。
2.2、基于注解的配置實現
基于注解的配置實現,簡單的說就是采用注解來開發,具體實現如下。
2.2.1、創建數據庫表
首先,mybatis框架不會幫助我們根據實體類自動生成目標數據庫表,因此我們需要事先設計好數據庫表結構,在此我們以角色表tb_role為例,具體創建命令如下。
CREATE TABLE `tb_role` (
`id` int(11) unsigned NOT NULL COMMENT '主鍵ID',
`role_name` varchar(50) DEFAULT NULL COMMENT '角色名稱',
`create_time` datetime DEFAULT NULL COMMENT '創建時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2.2.2、編寫對應的實體類
package com.example.springboot.entity;
public class Role {
/**
* 主鍵ID
*/
private Integer id;
/**
* 角色名稱
*/
private String roleName;
/**
* 創建時間
*/
private Date createTime;
// set、get方法等...
}
2.2.3、編寫對應的 Mapper 接口
package com.example.springboot.mapper;
public interface RoleMapper {
@Select("select * from tb_role")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "roleName", column = "role_name"),
@Result(property = "createTime", column = "create_time")
})
List<Role> findAll();
@Select("select * from tb_role where id =#{id}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "roleName", column = "role_name"),
@Result(property = "createTime", column = "create_time")
})
Role findById(@Param("id") Integer id);
@Insert("insert into tb_role(id, role_name, create_time) VALUES(#{id}, #{roleName}, #{createTime})")
int insert(Role role);
@Update("update tb_role set role_name=#{roleName} WHERE id=#{id}")
int update(Role role);
@Delete("delete from tb_role where id =#{id}")
int delete(@Param("id") Integer id);
}
2.2.4、添加 Mapper 接口掃描路徑
默認創建的 Mapper 接口無法被自動加載到 Spring IOC 容器中,因此需要在Application啟動類上,添加 Mapper 接口的包掃描路徑,可以通過@MapperScan注解來完成注入,具體如下。
@MapperScan("com.example.springboot.mapper")
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2.2.5、單元測試
最后,我們編寫單元測試來驗證一下內容的正確性,代碼如下:
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class RoleMapperJunit {
@Autowired
private RoleMapper roleMapper;
@Test
public void test(){
// 新增數據
roleMapper.insert(new Role(1, "開發工程師", new Date()));
roleMapper.insert(new Role(2, "測試工程師", new Date()));
roleMapper.insert(new Role(3, "項目經理", new Date()));
// 查詢數據
List<Role> roleList = roleMapper.findAll();
System.out.println("第一次查詢全部數據結果:" + roleList.toString());
System.out.println("----------------------");
// 修改單條數據
roleMapper.update(new Role(1, "技術經理"));
// 單條查詢
Role role = roleMapper.findById(1);
System.out.println("查詢[id=1]結果:" + role.toString());
System.out.println("----------------------");
// 刪除單條數據
roleMapper.delete(1);
// 查詢數據
List<Role> roleList1 = roleMapper.findAll();
System.out.println("第二次查詢全部數據結果:" + roleList1.toString());
}
}
運行單元測試,輸出結果如下!
第一次查詢全部數據結果:[Role{id=1, roleName='開發工程師', createTime=Sun Apr 28 11:44:52 CST 2024}, Role{id=2, roleName='測試工程師', createTime=Sun Apr 28 11:44:52 CST 2024}, Role{id=3, roleName='項目經理', createTime=Sun Apr 28 11:44:52 CST 2024}]
----------------------
查詢[id=1]結果:Role{id=1, roleName='技術經理', createTime=Sun Apr 28 11:44:52 CST 2024}
----------------------
第二次查詢全部數據結果:[Role{id=2, roleName='測試工程師', createTime=Sun Apr 28 11:44:52 CST 2024}, Role{id=3, roleName='項目經理', createTime=Sun Apr 28 11:44:52 CST 2024}]
至此,基于注解模式的實現方式已經介紹完畢了。
如果有一定開發經歷的同學可能會感覺到,基于注解方式的開發模式雖然簡單,但是弊端也很大,假如查詢的時候,需要連接的表很多,字段也多,代碼可讀性就變得很差,因此大多數情況下,開發者會更傾向于選擇基于 XML 的配置實現方式開發,原因是它的可讀性更高。
2.3、基于XML的配置實現
基于 XML 的配置實現,是一種最常用的開發模式,具體實現如下。
2.3.1、創建數據庫表
與上面類似,我們創建一張新表tb_menu來介紹,具體創建命令如下。
CREATE TABLE `tb_menu` (
`id` int(11) unsigned NOT NULL COMMENT '主鍵ID',
`menu_name` varchar(50) DEFAULT NULL COMMENT '菜單名稱',
`create_time` datetime DEFAULT NULL COMMENT '創建時間',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2.3.2、編寫對應的實體類
package com.example.springboot.entity;
public class Menu {
/**
* 主鍵ID
*/
private Integer id;
/**
* 菜單名稱
*/
private String menuName;
/**
* 創建時間
*/
private Date createTime;
// set、get方法等...
}
2.3.3、編寫對應的 Mapper 接口
與上面基于注解的開發模式類似,只是少了注解配置。
package com.example.springboot.mapper;
public interface MenuMapper {
List<Menu> findAll();
Menu findById(@Param("id") Integer id);
int insert(Menu role);
int update(Menu role);
int delete(@Param("id") Integer id);
}
2.3.4、創建 XML 映射文件
在src/main/resources/mybatis/mapper目錄下創建MenuMapper.xml文件,并與 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.springboot.mapper.MenuMapper">
<!--BaseResultMap-->
<resultMap id="BaseResultMap" type="com.example.springboot.entity.Menu" >
<id column="id" property="id" jdbcType="INTEGER" />
<result column="menu_name" property="menuName" jdbcType="VARCHAR" />
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
</resultMap>
<!--Base_Column_List-->
<sql id="Base_Column_List">
id
,menu_name
,create_time
</sql>
<select id="findAll" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from tb_menu
order by id
</select>
<select id="findById" resultMap="BaseResultMap" parameterType="java.lang.Integer">
select
<include refid="Base_Column_List"/>
from tb_menu
where id = #{id,jdbcType=INTEGER}
</select>
<insert id="insert" parameterType="com.example.springboot.entity.Menu">
insert into tb_menu(id, menu_name, create_time)
values(#{id}, #{menuName}, #{createTime})
</insert>
<update id="update" parameterType="com.example.springboot.entity.Menu">
update tb_menu
set menu_name = #{menuName,jdbcType=VARCHAR}
where id = #{id,jdbcType=INTEGER}
</update>
<delete id="delete" parameterType="java.lang.Integer">
delete from tb_menu
where id = #{id,jdbcType=INTEGER}
</delete>
</mapper>
2.3.5、創建 Mybatis 全局配置文件
在src/main/resources/mybatis目錄下創建mybatis-config.xml文件,可以全局配置 mybatis 相關屬性信息,示例如下:
<?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>
<!-- 指定MyBatis所用日志的具體實現,STDOUT_LOGGING:表示打印到控制臺-->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<typeAliases>
<!--配置類型別名可為Java類型設置一個縮寫名字,以便于在xml中通過簡寫來代替全限定類名-->
<typeAlias alias="Integer" type="java.lang.Integer" />
<typeAlias alias="Long" type="java.lang.Long" />
<typeAlias alias="HashMap" type="java.util.HashMap" />
<typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" />
<typeAlias alias="ArrayList" type="java.util.ArrayList" />
<typeAlias alias="LinkedList" type="java.util.LinkedList" />
</typeAliases>
</configuration>
更多的配置屬性,可以參考這篇文章。
2.3.6、添加 Mapper 接口掃描路徑
同上,需要在Application啟動類上添加 Mapper 接口的包掃描路徑,如果已添加,可以忽略。
@MapperScan("com.example.springboot.mapper")
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2.3.7、配置 XML 文件掃描路徑
與基于注解的開發模式稍有不同,我們還需要在application.properties文件中配置 Mybatis 相關的 XML 文件掃描目錄,否則啟動報錯,內容如下:
# 配置mybatis全局配置文件掃描
mybatis.config-location=classpath:mybatis/mybatis-config.xml
# 配置mybatis的xml配置文件掃描目錄
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
# 打印SQL語句,需要注射掉這個mybatis全局屬性配置,否則啟動報錯
#mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
2.3.8、單元測試
最后,我們編寫單元測試來驗證一下內容的正確性,代碼如下:
public class MenuMapperJunit {
@Autowired
private MenuMapper menuMapper;
@Test
public void test(){
// 新增數據
menuMapper.insert(new Menu(1, "用戶菜單", new Date()));
menuMapper.insert(new Menu(2, "角色菜單", new Date()));
menuMapper.insert(new Menu(3, "系統菜單", new Date()));
// 查詢數據
List<Menu> menuList = menuMapper.findAll();
System.out.println("第一次查詢全部數據結果:" + menuList.toString());
System.out.println("----------------------");
// 修改單條數據
menuMapper.update(new Menu(1, "項目菜單"));
// 單條查詢
Menu menu = menuMapper.findById(1);
System.out.println("查詢[id=1]結果:" + menu.toString());
System.out.println("----------------------");
// 刪除單條數據
menuMapper.delete(1);
// 查詢數據
List<Menu> menuList1 = menuMapper.findAll();
System.out.println("第二次查詢全部數據結果:" + menuList1.toString());
}
}
運行單元測試,輸出結果如下!
第一次查詢全部數據結果:[Menu{id=1, menuName='用戶菜單', createTime=Sun Apr 28 14:24:49 CST 2024}, Menu{id=2, menuName='角色菜單', createTime=Sun Apr 28 14:24:49 CST 2024}, Menu{id=3, menuName='系統菜單', createTime=Sun Apr 28 14:24:50 CST 2024}]
----------------------
查詢[id=1]結果:Menu{id=1, menuName='項目菜單', createTime=Sun Apr 28 14:24:49 CST 2024}
----------------------
第二次查詢全部數據結果:[Menu{id=2, menuName='角色菜單', createTime=Sun Apr 28 14:24:49 CST 2024}, Menu{id=3, menuName='系統菜單', createTime=Sun Apr 28 14:24:50 CST 2024}]
至此,基于 XML 模式的實現方式已經介紹完畢了。
實際開發過程中,如果不需要自定義全局配置 Mybatis 數據,也可以省掉創建 Mybatis 全局配置文件這一步。
03、小結
本文主要圍繞利用 Mybatis 框架來實現對數據庫表的快速訪問操作,與 Spring Boot JPA 相比,Mybatis 在使用上更加靈活,對數據表的操作就像在本地數據庫寫 SQL 一樣方便,對于業務復雜的查詢場景,它比 Spring Boot JPA 要靈活很多。而且可維護性更高。
如果是企業級的 web 項目,推薦采用 Mybatis 框架作為持久層。
04、參考
- https://mybatis.net.cn/