文章目录
前言
在实际SpringBoot项目开发中,更多的场景是整合成熟的持久层框架来完成与数据库的交互。
目前比较流行的持久层框架包括SpringData JPA(底层默认依赖Hibernate)和MyBatis。
SpringData本身属于Spring生态的一部分,而MyBatis是第三方框架。
本章以MyBatis整合SpringBoot的核心场景启动器为切入点,研究MyBatis如何完成与SpringBoot的场景整合。
第11章 SpringBoot整合MyBatis
11.1 MyBatis框架概述
MyBatis是一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。
MyBatis免除了几乎所有的JDBC代码,支持通过简单的XML或注解来配置和映射原始类型、接口、POJO为数据库中的记录。
MyBatis的架构可以分为三层:
- 接口层:SqlSession是与MyBatis完成交互的核心接口。
- 核心层:SqlSession执行的方法,包括配置文件的解析、SQL解析、执行SQL时的参数映射、SQL执行、结果集映射等。
- 支持层:核心层的功能实现是基于支持层的各个模块共同协调完成的。
11.2 SpringBoot整合MyBatis项目搭建
搭建如下图所示的项目:
实体类:
public class User {
private Integer id;
private String name;
private String tel;
// getter setter toString ...
}
Service类:
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional(rollbackFor = Exception.class)
public void test() {
User user = new User();
user.setName("天蓬元帅");
user.setTel("12345");
userMapper.save(user);
List<User> userList = userMapper.findAll();
userList.forEach(System.out::println);
}
}
Mapper接口:
@Mapper
public interface UserMapper {
public void save(User user);
public List<User> findAll();
}
XML映射文件 UserMapper.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.star.springboot.mybatis.mapper.UserMapper">
<insert id="save" parameterType="User">
insert into t_user (name, tel) values (#{name}, #{tel})
</insert>
<select id="findAll" resultType="User">
select * from t_user
</select>
</mapper>
全局配置文件 application.properties:
# 数据源配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot_demo?characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456
# MyBatis配置
# 配置XML文件的路径
mybatis.mapper-locations=classpath*:**Mapper.xml
# 开启实体类别名映射
mybatis.type-aliases-package=com.star.springboot.mybatis.entity
# 开启驼峰规则
mybatis.configuration.map-underscore-to-camel-case=true
主启动类:
@SpringBootApplication
public class MyBatisApp {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(MyBatisApp.class, args);
UserService userService = context.getBean(UserService.class);
userService.test();
}
}
执行主启动类的main
方法,控制台打印结果如下:
User{id=1, name='天蓬元帅', tel='12345'}
说明SpringBoot整合MyBatis项目搭建成功。
11.3 自动装配的核心
在上面的项目搭建中,只需要写简单的几行代码和少量配置,底层的自动配置类完成了大多数组件的装配和配置的应用。
11.3.1 mybatis-spring-boot-starter
打开依赖包mybatis-spring-boot-starter,发现它只是一个空的jar包,没有具体的内容:
进入该依赖包的pom.xml文件,发现它本身又依赖mybatis-spring-boot-autoconfigure。
源码1:mybatis-spring-boot-starter-2.1.3.jar!/META-INF/maven/org.mybatis.spring.boot/mybatis-spring-boot-starter/pom.xml
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-autoconfigure</artifactId>
</dependency>
打开依赖包mybatis-spring-boot-autoconfigure,发现它包含一个spring.factories文件,这个文件中定义了两个自动配置类:
源码2:mybatis-spring-boot-autoconfigure/2.1.3/mybatis-spring-boot-autoconfigure-2.1.3.jar!/META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\
org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
由此可知,SpringBoot整合MyBatis的核心装配就在这两个自动配置类上。
11.3.2 MybatisLanguageDriverAutoConfiguration
从类名可知,MybatisLanguageDriverAutoConfiguration是一个与“语言驱动”相关的自动配置类。
MyBatis默认使用XML作为编写映射文件的实现,而从MyBatis 3.2版本开始支持第三方模板引擎框架作为编写映射文件的实现。
查阅MybatisLanguageDriverAutoConfiguration的源码可知,MyBatis支持的第三方模板引擎框架包括FreeMarker、Thymeleaf、Velocity等。但默认情况下,MyBatis不会引入这些模板引擎框架的依赖,因此使用IDE打开这个自动配置类时会产生error提示。
11.3.3 MybatisAutoConfiguration
相比之下,MybatisAutoConfiguration才是MyBatis整合SpringBoot的核心,MyBatis内部支撑运行的所有组件都在这个配置类中创建。
11.3.3.1 SqlSessionFactory
SqlSessionFactory是MyBatis底层核心支撑,有了SqlSessionFactory就可以创建SqlSession,进而使用SqlSession的CRUD操作。
源码3:MybatisAutoConfiguration.java
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
// 设置数据源
factory.setDataSource(dataSource