Spring Boot 集成 MyBatis
1. 前言
企業(yè)級應(yīng)用數(shù)據(jù)持久層框架,最常見的應(yīng)該是 Hibernate 和 MyBatis 。
Hibernate 是相當(dāng)徹底的 ORM 對象 - 關(guān)系映射框架,使用 Hibernate ,開發(fā)者可以不考慮 SQL 語句的編寫與執(zhí)行,直接操作對象即可。
與 Hibernate 相比, MyBatis 還是需要手工編寫 SQL 語句的。恰好由于互聯(lián)網(wǎng)行業(yè)數(shù)據(jù)量非常巨大,對 SQL 性能有比較苛刻的要求,往往都需要手工編寫 SQL 。在此背景下, MyBatis 逐漸流行。
除此之外,MyBatis 是更加簡單,更容易上手的框架,但是功能也是相對簡陋點(diǎn)。
本篇就演示下,如何在 Spring Boot 框架中快速集成并使用 MyBatis 。
2. 實(shí)例場景
本篇我們使用 Spring Boot 與 MyBatis ,開發(fā)一個(gè)商城系統(tǒng)中商品管理模塊后端部分。我們依然遵循 Restful 風(fēng)格,以便團(tuán)隊(duì)小伙伴快速理解與接入。
3. 數(shù)據(jù)庫模塊實(shí)現(xiàn)
我們新建數(shù)據(jù)庫 shop ,其中包含商品表,結(jié)構(gòu)定義如下:
CREATE TABLE `goods` (
`id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '唯一編號(hào)',
`name` varchar(255) DEFAULT '' COMMENT '商品名稱',
`price` decimal(10,2) DEFAULT '0.00' COMMENT '商品價(jià)格',
`pic` varchar(255) DEFAULT '' COMMENT '圖片文件名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
4. Spring Boot 后端實(shí)現(xiàn)
接下來,我們可以開發(fā) Spring Boot 后端項(xiàng)目了,并使用 MyBatis 作為數(shù)據(jù)持久層框架。
4.1 使用 Spring Initializr 創(chuàng)建項(xiàng)目
Spring Boot 版本選擇 2.2.5 ,Group 為 com.imooc
, Artifact 為 spring-boot-mybatis
,生成項(xiàng)目后導(dǎo)入 Eclipse 開發(fā)環(huán)境。
4.2 引入項(xiàng)目依賴
我們引入 Web 項(xiàng)目依賴、熱部署依賴。由于本項(xiàng)目需要訪問數(shù)據(jù)庫,所以引入 spring-boot-starter-jdbc
依賴和 mysql-connector-java
依賴。由于項(xiàng)目中使用了 MyBaits ,所以還需要引入 mybatis-spring-boot-starter
依賴。本節(jié)實(shí)例開發(fā)完成后會(huì)使用 JUnit 進(jìn)行測試,所以引入 junit
依賴。
最終,pom.xml 文件中依賴項(xiàng)如下:
實(shí)例:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 熱部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- Web支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- JDBC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- MySQL驅(qū)動(dòng) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 集成MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- 測試 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
4.3 數(shù)據(jù)源配置
修改 application.properties
文件,配置數(shù)據(jù)源信息。Spring Boot 會(huì)將數(shù)據(jù)源自動(dòng)注入到 MyBatis 的 sqlSessionFactory 組件中。對于我們開發(fā)者來說,這一切都是自動(dòng)實(shí)現(xiàn)的, MyBatis 同樣可以開箱即用,簡單到爆炸。
實(shí)例:
# 配置數(shù)據(jù)庫驅(qū)動(dòng)
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 配置數(shù)據(jù)庫url
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/shop?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
# 配置數(shù)據(jù)庫用戶名
spring.datasource.username=root
# 配置數(shù)據(jù)庫密碼
spring.datasource.password=Easy@0122
4.4 開發(fā)數(shù)據(jù)對象類
開發(fā) goods 表對應(yīng)的數(shù)據(jù)對象類 GoodsDo ,代碼如下:
實(shí)例:
/**
* 商品類
*/
public class GoodsDo {
/**
* 商品id
*/
private Long id;
/**
* 商品名稱
*/
private String name;
/**
* 商品價(jià)格
*/
private String price;
/**
* 商品圖片
*/
private String pic;
// 省略 get set方法
}
4.5 開發(fā)數(shù)據(jù)訪問層
數(shù)據(jù)訪問層直接使用接口實(shí)現(xiàn)即可,接口中添加商品的增刪改查基本操作。
實(shí)例:
/**
* 商品數(shù)據(jù)庫訪問接口
*/
@Repository // 標(biāo)注數(shù)據(jù)訪問組件
public interface GoodsDao {
/**
* 新增商品
*/
public int insert(GoodsDo Goods);
/**
* 刪除商品(根據(jù)id)
*/
public int delete(Long id);
/**
* 修改商品信息(根據(jù)id修改其他屬性值)
*/
public int update(GoodsDo Goods);
/**
* 查詢商品信息(根據(jù)id查詢單個(gè)商品信息)
*/
public GoodsDo selectOne(Long id);
/**
* 查詢商品列表
*/
public List<GoodsDo> selectAll();
}
然后,我們修改 Spring Boot 配置類,添加 @MapperScan
注解,掃描數(shù)據(jù)訪問接口所在的包,
實(shí)例:
@SpringBootApplication
@MapperScan("com.imooc.springbootmybatis") // 指定MyBatis掃描的包,以便將數(shù)據(jù)訪問接口注冊為bean
public class SpringBootMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootMybatisApplication.class, args);
}
}
4.6 添加 MyBatis 映射文件
編寫數(shù)據(jù)訪問層接口之后,MyBatis 需要知道,如何將接口方法及參數(shù)轉(zhuǎn)換為 SQL 語句,以及 SQL 語句執(zhí)行結(jié)果如何轉(zhuǎn)換為對象。這些都是通過映射文件描述的, MyBatis 映射文件就是描述對象 - 關(guān)系映射的配置文件。
首先我們通過 application.properties
指定映射文件的位置:
實(shí)例:
# 指定MyBatis配置文件位置
mybatis.mapper-locations=classpath:mapper/*.xml
然后在 resources/mapper
目錄下新建 GoodsMapper.xml
文件,該文件就是 goods 表對應(yīng)的映射文件,內(nèi)容如下:
實(shí)例:
<?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">
<!-- 本映射文件對應(yīng)GoodsDao接口 -->
<mapper namespace="com.imooc.springbootmybatis.GoodsDao">
<!-- 對應(yīng)GoodsDao中的insert方法 -->
<insert id="insert" parameterType="com.imooc.springbootmybatis.GoodsDo">
insert into goods (name,price,pic) values (#{name},#{price},#{pic})
</insert>
<!-- 對應(yīng)GoodsDao中的delete方法 -->
<delete id="delete" parameterType="java.lang.Long">
delete from goods where id=#{id}
</delete>
<!-- 對應(yīng)GoodsDao中的update方法 -->
<update id="update" parameterType="com.imooc.springbootmybatis.GoodsDo">
update goods set name=#{name},price=#{price},pic=#{pic} where id=#{id}
</update>
<!-- 對應(yīng)GoodsDao中的selectOne方法 -->
<select id="selectOne" resultMap="resultMapBase" parameterType="java.lang.Long">
select <include refid="sqlBase" /> from goods where id = #{id}
</select>
<!-- 對應(yīng)GoodsDao中的selectAll方法 -->
<select id="selectAll" resultMap="resultMapBase">
select <include refid="sqlBase" /> from goods
</select>
<!-- 可復(fù)用的sql模板 -->
<sql id="sqlBase">
id,name,price,pic
</sql>
<!-- 保存SQL語句查詢結(jié)果與實(shí)體類屬性的映射 -->
<resultMap id="resultMapBase" type="com.imooc.springbootmybatis.GoodsDo">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="price" property="price" />
<result column="pic" property="pic" />
</resultMap>
</mapper>
5. 測試
我們直接編寫測試類,對數(shù)據(jù)訪問接口進(jìn)行測試。此處通過 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
注解,使測試方法按名稱順序依次執(zhí)行。這樣就可以一次性測試 GoodsDao 中的所有方法了,具體測試代碼如下:
實(shí)例:
/**
* GoodsDao測試類
*/
@SpringBootTest
@FixMethodOrder(MethodSorters.NAME_ASCENDING) // 按方法名稱順序測試
class GoodsDaoTest {
@Autowired
private GoodsDao goodsDao;
/**
* 新增一個(gè)商品
*/
@Test
void test_01() {
GoodsDo goods = new GoodsDo();
goods.setName("手機(jī)");
goods.setPic("phone.jpg");
goods.setPrice("2000");
int count = goodsDao.insert(goods);
assertEquals(1, count);// count值為1則測試通過
}
/**
* 更新商品信息
*/
@Test
void test_02() {
GoodsDo goods = new GoodsDo();
goods.setId(1L);
goods.setName("手機(jī)");
goods.setPic("phone.jpg");
goods.setPrice("3000");
int count = goodsDao.update(goods);
assertEquals(1, count);// count值為1則測試通過
}
/**
* 獲取商品信息
*/
@Test
void test_03() {
GoodsDo goods = goodsDao.selectOne(1L);
assertNotNull(goods);// goods不為null則測試通過
}
/**
* 刪除商品
*/
@Test
void test_04() {
int count = goodsDao.deletex(1L);//此處應(yīng)為delete(1L)
assertEquals(1, count);// count值為1則測試通過
}
/**
* 獲取商品信息列表
*/
@Test
void test_05() {
List<GoodsDo> goodsList = goodsDao.selectAll();
assertEquals(0, goodsList.size());// goodsList.size()值為0則測試通過
}
}
測試結(jié)果如下,說明所有測試都通過了。
6. 小結(jié)
MyBatis 可以自由的編寫 SQL 語句,開發(fā)人員可以充分發(fā)揮 SQL 語句的性能。
Spring Boot 中使用 MyBatis 操作數(shù)據(jù)庫十分方便,引入相關(guān)依賴后,定義數(shù)據(jù)訪問接口,然后通過映射文件描述對象 - 關(guān)系映射即可。當(dāng)然不要忘記通過 MapperScan
注解掃描數(shù)據(jù)訪問接口所在的包,以便發(fā)現(xiàn)和注冊相關(guān)的組件。
MyBatis 還有一些簡化開發(fā)的工具和框架,如 MyBatis-Plus 、 MyBatis-Generator ,可以簡化 MyBatis 開發(fā)過程,在一定程度上提高開發(fā)效率。感興趣的同學(xué)可以通過網(wǎng)絡(luò)獲取相關(guān)資料進(jìn)一步學(xué)習(xí)。