前面,我们将数据库环境在本地搞定了,是时候来搞定Spring Boot与Mybatis的整合了。废话不多说,开整!
拷贝工程
我们要保留之前的hello boot的版本,因此基于它拷贝一份,改个名字叫hello-mybatis,注意settings.gradle中也要改名:
rootProject.name = 'hello-mybatis'
这样我们就拷贝出一个新的项目:
直接用idea打开后,刷新gradle,让它自动构建ok。
后续,我们每小节新内容的开发也同样采用这种方式:保留前一节的项目源码,在此基础上复制一份新的来开发。这种非协同的开发(一个人的学习)也无需使用版本控制工具,手动拷贝也不麻烦嘛。
引入依赖
要整合mybatis,先引入必须的依赖:
dependencies {
...
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2'
runtimeOnly "com.h2database:h2"
}
注意这里的mybatis依赖需要指定版本,它不在依赖管理的清单中,h2数据库的驱动则不需要指定版本,但是注意这里的依赖范围为仅为运行时依赖。
当我们将第三方的起始依赖(xxx-spring-boot-starter)放到了类路径上后,spring boot会按照默认的设置完成第三方模块的自动装配。
用户可以通过spring boot的配置文件来修改默认的配置,这里我们可以指定下数据源,新增一个application.yml
(如果不存在的话),在其中指定配置:
spring:
datasource: # 数据源的相关配置
platform: h2
type: com.zaxxer.hikari.HikariDataSource # 数据源类型:HikariCP
driver-class-name: org.h2.Driver # h2驱动
url: jdbc:h2:tcp://localhost/~/db_juan_mall;DB_CLOSE_DELAY=-1;MODE=MySQL;AUTO_SERVER=TRUE;AUTO_RECONNECT=TRUE
username: sa
password:
hikari:
connection-timeout: 30000 # 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 默认:30秒
minimum-idle: 5 # 最小连接数
maximum-pool-size: 20 # 最大连接数
auto-commit: true # 自动提交
idle-timeout: 600000 # 连接超时的最大时长(毫秒),超时则被释放(retired),默认:10分钟
pool-name: DateSourceHikariCP # 连接池名字
max-lifetime: 1800000 # 连接的生命时长(毫秒),超时而且没被使用则被释放(retired),默认:30分钟 1800000ms
connection-test-query: SELECT 1
开发持久层
model
首先我们开发和数据库持久化相关的实体类:
package com.xiaojuan.boot.dao.model;
import ...
@Data
public class Category {
private Long id;
private Long pid;
private String name;
private Byte level;
private Byte orderNum;
private Date createTime;
private Date updateTime;
}
mapper接口
mybatis的dao组件叫做mapper,它会采用动态代理机制在运行时生成接口的目标代理对象来执行数据库的curd操作。而在开发时,开发人员只需要关注接口的定义即可。这里我们采用mybatis提供的curd相关的注解方式,将编写的sql语句与mapper接口的方法进行绑定。
package com.xiaojuan.boot.dao.mapper;
import ...
public interface CategoryMapper {
@Select("select * from tb_category")
List<Category> listAllCategories();
}
以上定义的接口,小伙伴们发现,接口上并没有加任何的注解修饰。mybatis提供了mapper包扫描的注解,可以让用户来指定要在那些包下扫描mapper接口,使它可以自动识别这些mapper接口。
Mapper配置
package com.xiaojuan.boot.dao;
import ...
@Configuration
@MapperScan({"com.xiaojuan.boot.dao.**.mapper"})
public class MapperConfig {
}
编写单元测试
这里我们采用的是spring boot框架提供的测试模块来很方便的完成单元测试的编写。这里我们用的是junit5的jupiter-api提供的特性来进行断言的,关于junit5的断言特性,在我们后续的单元测试中会有更多使用。
还要注意这里的测试类上我们加了一个@Transactional
注解,这样确保每个单元测试执行完成后事务都会回滚,数据不会进库从而影响下一次跑单元测试。
package com.xiaojuan.boot.dao.mapper;
import ...
import static org.junit.jupiter.api.Assertions.*;
@Transactional // 确保每个单元测试后数据会回滚,实现单元测试数据的隔离
@SpringBootTest
public class CategoryMapperTest {
@Resource
private CategoryMapper categoryMapper;
@Test
public void testListAllCategories() {
List<Category> categories = categoryMapper.listAllCategories();
assertEquals(3, categories.size());
}
}
增加sql日志输出
默认spring boot已经集成了日志框架的实现模块,这里要进行日志输出的配置,同样修改应用配置即可。这里我们对mapper包进行trace级别的日志输出,这样mybatis执行mapper输出的trace日志就能在控制台显示出来了。
application.yml
logging:
level:
com.xiaojuan.boot.dao.mapper: trace
xml形式的mapper实现
在xml中定义mapper接口对应的curd的sql手写实现,还可以对结果集进行映射处理,以及mybatis提供的其他高级特性的实现在mybatis xml形式的mapper定义中都可以做到。这里我们将写一个最简单的sql查询语句块。
去除idea中xml背景色
首先去除idea中mybatis xml的sql背景色。因为,默认idea会对mybatis中sql语句的背景色按某些检查要求加黄色的背景色以示警告,而这对我们来说并不是配置错误,可以无视,为了不受干扰,我们做些设置把背景色去掉:
搜索“No data sources configure”
搜索“SQL dialect detection”
搜索“Injected language fragment”
mapper开发
在mapper接口中增加方法:
package com.xiaojuan.boot.dao.mapper;
import ...
public interface CategoryMapper {
...
List<Category> loadAllCategories();
}
resources/mapper/category-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.xiaojuan.boot.dao.mapper.CategoryMapper">
<select id="loadAllCategories" resultType="com.xiaojuan.boot.dao.model.Category">
select id, pid, name, level, order_num, create_time, update_time from TB_CATEGORY
</select>
</mapper>
mapper xml配置
application.yml
mybatis:
mapper-locations: classpath:mapper/**/*.xml
configuration:
# 下划线到驼峰的映射
map-underscore-to-camel-case: true
测试用例
package com.xiaojuan.boot.dao.mapper;
import ...
...
public class CategoryMapperTest {
...
@Test
public void testLoadAllCategories() {
List<Category> categories = categoryMapper.loadAllCategories();
assertEquals(3, categories.size());
}
}
这一节,我们对spring boot与mybatis做了一个快速的整合,这得益于spring boot起始依赖和自动装配的特性以及application可定制的配置。这里我们采用了@SpingBootTest
的注解方式来启动spring boot单元测试进行mapper接口的测试的,关于单元测试我们下一节会有更详细的介绍,大家加油!