集成MyBatis
# 5.2 Spring Boot 集成 MyBatis
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
官方参考文档 (opens new window),有中文版,描述非常详细,在这里,能解决你的所有疑问。
由于 MyBatis 在系统复杂性、便捷性和可控性方面找到了一个较好平衡。能够满足 DBA 对数据库的架构设计,也能满足开发人员对复杂 SQL 的编写,同时又能满足技术经理/架构师对 SQL 调优的需求。所以,最近几年来,MyBatis 使用得越来越广泛。
要想掌握 MyBatis,必须熟悉其几个重要的概念:
- **mapper:**映射器,里面存放了增删改查等映射语句和其对应的 java 接口(在运行时使用 动态代理),通常情况下,我们指一个 mapper 是在说这个 mapper 的 xml 文件和其对应的接口 java 文件。MyBatis 的真正强大在于它的映射语句,也是它的魔力所在。由于它的异常强大,映射器(mapper)的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 就是针对 SQL 构建的,并且比普通的方法做的更好。
- **namespace:**命名空间。在之前版本的 MyBatis 中,命名空间的作用并不大,是可选的。 但现在,随着命名空间越发重要,你必须指定命名空间。命名空间的作用有两个。
- 利用更长的完全限定名来将不同的语句隔离开来,同时将 mapper 的 xml 文件和 java 接口绑定。
- 将命名空间置于合适的 java 包命名空间之中,代码会变得更加整洁,也有利于你更方便地使用 MyBatis。
- **resultType:**返回结果类型。例如如一个按照 id 查询的 select 语句返回表中一条记录,MyBatis 通过 mapper,在 java 中将其映射成一个对象返回。
MyBatis 中的概念较多,对应使用到的文件也较多,为了更加形象的理解 MyBatis 的配置对应关系,我们通过如下 Spring Boot 项目的 MyBatis 配置关系示意图,来学习如何正确地将 MyBatis 的各种元素有机的联系起来。
如上图所示:
- 红色 mapper 2.1 指定了项目中 mapper 映射 xml 文件(例如上图中的 2.1* UserMapper.xml 文件,其中存放了 select 等语句)存放的位置(大多数项目都习惯于将其存放于 resources/mapping 文件夹下);
- 红色 namespace 命名空间 2.2 将本 mapper 映射 xml 文件和对应的 java 接口文件(2.2*)连接起来;
- 蓝色1.1的
type-aliases-package
指定了1.2resultType
的简写方法(上图中的 1.2User
会被MyBatis解释成com.example.mybatis.entity.User
); - 蓝色返回类型 1.2User(实际上是
com.example.mybatis.entity.User
)对应的是 1.4 包下的 entity 实体类 1.3User; - 绿色 3.1selectUser 是一个 select 查询,其对应的 java 接口文件中的方法为 3.1**selectUser 方法,返回类型为蓝色 1.2User;
- 绿色 3.1selectUser 这个 select 查询,使用了一个 3.2id 参数,对应 java 接口文件 3.1** selectUser 方法参数 3.2**id;
- 紫色 4.1
@MapperScan("com.example.mybatis.mapper")
注解指定了 mapper 的 java 接口文件扫描的包位置 4.1*,上图中,红色 2.2UserMapper 接口文件就存放在其中。
application.yml 配置文件中(红色2.1)设定了 mapper 的 xml 文件存放位置;
Spring Boot 配置类(本例中将其配置到了 Spring Boot 的启动类上了)中,设定了 mapper 的 java 接口文件扫描位置。在项目启动时,MyBatis 将扫描(扫描
@Repository
注解)到的 mapper 的 java 接口文件和 mapper 的 xml 动态代理成我们真正用到的 Dao 类,完成数据库的访问,并返回映射后的 java 对象,完成 ORM(对象关系映射)过程。
Spring Boot 通过 starter 使用 MyBatis 是非常方便的。
在 pom.xml 文件中添加mybatis-spring-boot-starter
启动器,和 MySQL 数据的 jdbc 驱动,就可以使用 MyBatis 了。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2
3
4
5
6
7
8
9
10
需要注意的是:在我们的练习环境中使用的是 MySQL 5.7 数据库,Spring Boot 使用当前的 jdbc驱动(8.0.18)application.yml 配置需要注意如下两点:
- url 需要设置时区参数,例如
jdbc:mysql://localhost:3306/spring_boot_course?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
;- jdbc 驱动,需要使用
com.mysql.cj.jdbc.Driver
。
# 5.2.1 创建项目
首先在 STS 中创建一个 Spring Boot 项目,选中的 starter 有:
- Spring Web;
- MySQL Driver;
- MyBatis Framework.
其 pom.xml 文件内容如下:
<?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.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>mybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>MyBatis</name>
<description>MyBatis Example.</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>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 5.2.2 修改配置文件
在 application.yml 文件中配置数据库连接信息:
# mysql数据源配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/spring_boot_course?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# mybatis 配置信息
mybatis:
mapper-locations: classpath:mapping/*Mapper.xml
type-aliases-package: com.example.mybatis.entity
2
3
4
5
6
7
8
9
10
11
# 5.2.3 启动类
启动类,也是一个配置类(@SpringBootApplication
是个复合注解),可在上配置 MyBatis 的扫描注解。
package com.example.mybatis;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.mybatis.mapper")
public class MyBatisApplication {
public static void main(String[] args) {
SpringApplication.run(MyBatisApplication.class, args);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
其中第 8 行是添加的 MyBatis 的 mapper 扫描包位置。
项目中通常会包含多个业务功能模块,mapper 会放置在各自功能模块下的 mapper 包中,请参考如下代码配置多个扫描包位置:
@MapperScan({"com.example.mybatis.admin.mapper","com.example.mybatis.report.mapper"})
# 5.2.4 实体类
实体类,一般对应了数据库中的表。
package com.example.mybatis.entity;
public class User {
private Integer id;
private String userName;
private String passWord;
private String realName;
(省略getter、setter和toString方法)
2
3
4
5
6
7
8
9
对应表 user 的 MySQL DDL 如下:
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(32) NOT NULL AUTO_INCREMENT,
`userName` varchar(32) NOT NULL,
`passWord` varchar(50) NOT NULL,
`realName` varchar(32) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
2
3
4
5
6
7
8
插入 1 条数据,供测试:
INSERT INTO `user` VALUES ('1', 'Kevin', '123456', '长的帅');
# 5.2.5 映射器(mapper)
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.mybatis.mapper.UserMapper">
<select id="selectUser" resultType="User">
select * from user where id = #{id}
</select>
</mapper>
2
3
4
5
6
7
8
9
mapper 的 java 接口文件:
package com.example.mybatis.mapper;
import org.springframework.stereotype.Repository;
import com.example.mybatis.entity.User;
@Repository
public interface UserMapper {
User selectUser(int id);
}
2
3
4
5
6
7
8
9
10
11
注意第 7 行的注解,标注了这是个受 MyBatis(Spring) 管理的 DAO 类(接口)。
# 5.2.6 服务类
服务类完成业务功能。一般企业应用,都会在服务类中注入 DAO 来操作数据库。
package com.example.mybatis.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.mybatis.entity.User;
import com.example.mybatis.mapper.UserMapper;
@Service
public class UserService {
@Autowired
UserMapper userMapper;
public User selectUser(int id){
return userMapper.selectUser(id);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
其中第 11-12 行,就注入了UserMapper
这个 DAO。
# 5.2.7 控制器类
控制器类与前端交互,并调用服务类完成业务操作。
package com.example.mybatis.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.mybatis.service.UserService;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("get/{id}")
public String getUser(@PathVariable int id){
return userService.selectUser(id).toString();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
其中第 14-15 行,就注入了服务类UserService
。
# 5.2.8 运行验证
运行该项目的启动类MyBatisApplication
,在浏览器中访问http://localhost:8080/user/get/1 (opens new window),验证是否可以正确的查询到数据库中的记录。
以上,就是 Spring Boot 如何集成使用 MyBatis 的方法。至于进一步的 MyBatis 进阶使用,会包括在后续的分页插件、MyBatis Plus 章节介绍。
更加详细的 MyBatis 中的 SQL 映射应该怎么写,请参考官方文档 (opens new window)。
本小节示例项目代码:
https://github.com/gyzhang/SpringBootCourseCode/tree/master/spring-boot-mybatis (opens new window)