SpringBoot整合Mybatis超详细流程

文章目录

前言

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作

MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Ordinary Java Object,普通老式 Java 对象)为数据库中的记录。

3.Springboot整合mybaties - 图1

因为 Mybatis的性能非常不错,SpringBoot 官方推荐使用 Mybatis 来连接数据库进行 CRUD 操作。

Mybatis的官方文档地址:https://mybatis.org/mybatis-3/zh/index.html

详细流程

0.引入Mybatis

建立项目后记得更改端口号为8081,我们之后的页面访问都会在8081端口。

我们使用 IDEA 建立一个 SpringBoot 项目,创建项目的流程可以回顾 SpringBoot入门

初始化组件部分选择 Web、JDBC API、MyBatis Framework、MySQL Driver

3.Springboot整合mybaties - 图2

项目初始化完成之后,可以在 pom.xml 文件中看到如下依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-jdbc</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.mybatis.spring.boot</groupId>
  7. <artifactId>mybatis-spring-boot-starter</artifactId>
  8. <version>2.1.3</version>
  9. </dependency>
  10. <dependency>
  11. <groupId>mysql</groupId>
  12. <artifactId>mysql-connector-java</artifactId>
  13. <scope>runtime</scope>
  14. </dependency>

1.创建数据

我们使用 Navicat 连接 MySql 数据库,在 Navicat 图形界面中创建一些简单的数据。

  1. 创建数据库,名字叫 zzz

命令行:

  1. create database if not exists zzz default charset utf8 collate utf8_general_ci;
  2. 1

或者直接使用呢图形界面快速建立数据库

3.Springboot整合mybaties - 图3

  1. 建立数据表 user
  1. create table user(
  2. id INT UNSIGNED auto_increment,
  3. username varchar(20) not null,
  4. password varchar(30) not null,
  5. age INT not null,
  6. primary key(id)
  7. )charset=utf8;
  1. 利用图形界面插入几条数据,方便之后用来做简单的测试

3.Springboot整合mybaties - 图4

2.创建程序目录

我们在 com.example 目录下新建四个目录,分别是 controller、dao、entity、service。

  • controller层负责具体的业务模块流程的控制
  • entity层用于存放我们的实体类,与数据库中的属性值基本保持一致,实现set和get的方法
  • dao层主要是做数据持久层的工作,负责与数据库联络,封装了增删改查基本操作
  • service层主要负责业务模块的逻辑应用设计,具体要调用到已定义的DAO层的接口

然后在 resource 目录下新建 mapper 目录。这个 mapper 目录是用来存放 SQL 语句的地方。

3.Springboot整合mybaties - 图5

顺便提一下,我们知道的 MVC 框架,即 model-view-controller 三层架构。这里 model层=entity层,与数据库的数据表对应,view层和 controller层结合非常紧密,需要联合起来一起开发。可以简单理解为 view层是做前端界面的展示,controller层做业务模流程块的控制。

如果在网上看到有 mapper层这个概念,就记住,mapper层=dao层,就是对数据库进行数据持久化操作。

不管是什么框架,我们很多时候都会与数据库进行交互。如果遇到一个场景我们都要去写SQL语句,那么我们的代码就会很冗余。所以,我们就想到了把数据库封装一下,让我们的数据库的交道看起来像和一个对象打交道,这个对象通常就是DAO。当我们操作这个对象的时候,这个对象会自动产生SQL语句来和数据库进行交互,我们就只需要使用DAO就行了。

通常我们在DAO层里面写接口,里面有与数据打交道的方法。SQL语句通常写在mapper文件里面的

Service层是建立在DAO层之上的,建立了DAO层后才可以建立Service层,而Service层又是在Controller层之下的,因而Service层应该既调用DAO层的接口,又要提供接口给Controller层的类来进行调用,它刚好处于一个中间层的位置。每个模型都有一个Service接口,每个接口分别封装各自的业务处理方法。

3.理解后台访问流程

3.Springboot整合mybaties - 图6

用户从页面前端,也就是我们所说的 view 层进行查询访问,进入到 controller 层找到对应的接口,接 着 controller 进行对 service 层进行业务功能的调用,service 要进入 dao 层查询数据,dao 层调用 mapper.xml 文件生成 sql 语句到数据库中进行查询。

在数据库中查询到数据,dao 层拿到实体对象的数据,接着交付给 service 层,接着 service 进行业务 逻辑的处理,返回结果给 controller,controller 根据结果进行最后一步的处理,返回结果给前端页 面。

创建一个访问用户信息的流程为:entity->dao->mapper->service->controller,这里 mapper 指的是存放 SQL 语句的 xml 文件。

4.核心文件配置

这里我们可以使用 application.properties 文件,也可以使用 application.yml 文件来进行配置,当然推荐使用 application.yml 文件。

如果用 application.yml 在第一次启动项目的时候报错,项目右侧 maven -> lifecycle -> clean一下即可

  1. server:
  2. port: 8081
  3. spring:
  4. datasource:
  5. driver-class-name: com.mysql.cj.jdbc.Driver
  6. url: jdbc:mysql://127.0.0.1:3306/zzz?useUnicode=true & characterEncoding=utf-8 &
  7. useSSL=true & serverTimezone=Asia/Shanghai
  8. username: root
  9. password: 123456
  10. mybatis:
  11. mapper-locations: classpath:/mapper/*.xml
  12. type-aliases-package: com.example.entity

这里注意 com.mysql.jdbc.Driver 和 com.mysql.cj.jdbc.Driver。前者是 mysql-connector-java 5 中的,后者是 mysql-connector-java 6 中的(需要设置时区),相当于说一个是旧版,一个是新版。我们可以到 pom.xml 文件中查看 mysql 驱动版本,而现在基本都是 6 以上的新版本,所以直接使用后者即可。

特别强调一点,连接MySQL时使用的是spring.datasource.username,不要顺手打成spring.datasource.data-username,这个教训太深刻了

参数解读:

  • driver-class-name:mysql驱动
  • url:mysql连接的url,默认是3306端口,zzz是数据库名,useSSL是使用安全套阶层连接进行数据传输(如果true出错可以选择false),serverTimezone设置时区,亚洲时区请设置上海或者香港,不要设置北京,因为系统里没有这个时区
  • username 是用户名,password 是密码
  • mybatis.mapper-locations:用于将配置路径下的 * .xml 文件加载到 mybatis 中
  1. # 方法一:只有一个路径
  2. mybatis.mapper-locations= classpath:mapper/*.xml
  3. # 方法二:有多个路径
  4. mybatis.mapper-locations= classpath:mapper/.xml,classpath:mapper/user/.xml
  5. 12345
  • type-aliases-package:指定POJO扫描包来让 mapper.xml 文件的 resultType 自动扫描到自定义POJO,这样就不用每次指定完全限定名
  1. # mapper.xml文件中设置
  2. # 完全限定名
  3. <select id="getUsers" resultType="com.example.entity.User">
  4. # 指定了POJO扫描包之后
  5. <select id="getUsers" resultType="User">

5.编写entity

我们在编写entity时遵循POJO的思想。

这里需要提及“POJO最小侵入性编程”的概念,POJO(Plain Ordinary Java Object)意思是普通Java对象。类的成员是私有的,且有一系列的 setter and getter方法来提供访问。

POJO的内在含义是指那些没有从任何类继承、也没有实现任何接口,更没有被其它框架侵入的java对象。POJO的格式是用于数据的临时传递,它只能装载数据,作为数据存储的载体,而不具有业务逻辑处理的能力。

一般来讲,是 entity 中要取的数据应该和数据表相对应,但不一定要全部取出

我们在刚才建立的 entity 目录中新建 User 类,定义属性 id、username、age。

  1. public class User {
  2. private int id;
  3. private String username;
  4. private int age;
  5. public int getId() {
  6. return id;
  7. }
  8. public void setId(int id) {
  9. this.id = id;
  10. }
  11. public String getUsername() {
  12. return username;
  13. }
  14. public void setUsername(String username) {
  15. this.username = username;
  16. }
  17. public int getAge() {
  18. return age;
  19. }
  20. public void setAge(int age) {
  21. this.age = age;
  22. }
  23. }

按 alt+insert 键,生成 Getter and Setter 方法。

6.编写dao,注解@mapper和@Repository区别

springboot 集成 mybatis 开发有两种版本,注解版配置文件版

注解版不需要配置任何文件,拿来即用,主要依靠的是注解来生成 sql 语句。配置文件版与注解版相比,仅仅稍微复杂一点,两者的区别仅为mapper层处理的处理方式不一样。配置文件版多了一个xml文件,但是配置更加灵活,逻辑结构更加清晰,可读性更强。


注解版,用 @Mapper 注解标识,我们使用#{id}来标识参数。@Mapper 注解把 mapper 这个 DAO 交给 Spring 管理,不再写 mapper 映射文件

  1. @Mapper
  2. public interface UserDao {
  3. @Select("select * from user where id=#{id}")
  4. public User getUserById(int id);
  5. @Delete("delete from user where id=#{id}")
  6. public int deleteUserById(int id);
  7. }

配置文件版,需要给编写的 dao 增加注解 @Repository。

@Repository注解修饰哪个类,则表明这个类具有对对象进行CRUD(增删改查)的功能。

而且@Repository是@Component注解的一个派生品,所以被@Repository注解的类可以自动的被@ComponentScan 通过路径扫描给找到。因此@Repository注解的类也能@Autowired实现自动装配。

通常将dao接口注入到service层的时候,需要写@Resource这个注解。加上@Repository,就是springboot生成一个bean,自动注入service的相关引用中。

我们在 dao 目录中新建 UserDao 接口,定义好方法。

  1. /*
  2. 实现两个功能
  3. 1、根据用户id查询用户信息
  4. 2、查询同一年龄下的所有用户
  5. 返回一组数据我们用 List<E> 来存储,传递多个参数我们用 Map 来存储
  6. 例如 public List<User> selectById4(@Param("map") Map map);
  7. */
  8. @Repository
  9. public interface UserDao {
  10. //不使用@Param
  11. public User getUserById(Integer id);
  12. //使用@Param
  13. public User getUserById(@Param("id") int id);
  14. public List<User> getUserByAge(@Param("age") int age);
  15. }

我们推荐使用 @Param 进行传参,当映射器方法需要多个参数时,这个注解可以被用于:给映射器方法中的每个参数来取一个名字。这里有两点好处:

  1. 在 xml 文件中不需要再指定参数类型 parameterType
  2. 当传递对象时,使用 #{对象.属性} 可以更清晰地提示自己

如果不使用 @Param,多参数将会以它们的顺序位置和SQL语句中的表达式进行映射,这是默认的。

dao 层定义了接口,不需要写具体的实现类,我们只需要在 mapper 中将文件路径映射好就行了。DAO的实现原理:它是通过JDK动态代理方式实现的,我们在启动加载配置文件的时候,它会根据 mapper 的 xml文件去生成一个DAO的实现。

使用配置文件版时,我们还需要在主程序中通过使用@MapperScan可以指定要扫描的Mapper类的包的路径

@MapperScan是要spring启动时,扫描到所有的Mapper文件,并生成代理类交给spring容器管理;

对着 dao 目录点击鼠标右键,选择 copy reference 即可复制包路径,粘贴进 MapperScan 中即可。

  1. @MapperScan("com.example.dao")
  2. @SpringBootApplication
  3. public class SpringmybatisApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(SpringmybatisApplication.class, args);
  6. }
  7. }

7.编写Mapper

在 mapper 目录下新建 UserMapper.xml 文件。

mapper.xml 的文件头信息我们一般不会去记忆,都是直接从官网给出的教程中复制 xml 的头信息,网址是:https://mybatis.org/mybatis-3/zh/getting-started.html

3.Springboot整合mybaties - 图7

我们需要更改命名空间 namespace 使之对应我们编写的 DAO,SQL语句都写在 mapper 标签里面。

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.example.dao.UserDao">
  6. </mapper>

然后我们根据 UserDao 中要写的方法进行配置,为了方便展示,我们这里仅做查询,现在 UserDao 中有两个查询方法。

查询的话我们用 select 标签,id 指定为方法名,resultType指明返回类型,标签中间写 SQL 语句。因为我们已经配置了type-aliases-package,直接写 User 即可。

  1. <select id="getUserById" resultType="User">
  2. select * from `user` where id=#{id}
  3. </select>
  4. <select id="getUserById2" resultType="User">
  5. select * from `user` where age=#{age}
  6. </select>

我们在前面第四步核心文件配置的时候指定了 POJO 扫描包,所以这里 resultType 不需要完全限定名。

这里 user 表完全可以不写反引号,写反引号主要是为了方便我们区分,这是数据库的一个表

编写 Mapper.xml 文件主要注意三点:

  • namespace相对应
  • id相对应
  • resultType相对应

目前我们所讲的 resultType 返回单一类型的值,包括基础类型 String、Integer、Long,还有定义好的 Class 对象。

resultMap 则可以返回多个类型的值,适合多表连接查询。resultMap 的具体用法可以去官方文档中学习,这里我们不做过多的了解。

8.编写Service

我们需要在实现类中使用 @Service 注解,才能被 SpringBoot 扫描,在 Controller 中使用 @Autowired 注入

在 service 目录中新建 UserService 类

  1. //这里只使用 @Service 也可以,括号里的内容不影响
  2. @Service("UserService")
  3. public class UserService {
  4. }

使用 @Autowired 注解自动装配 UserDao。调用 dao 层接口设计逻辑应用

  1. @Service("UserService")
  2. public class UserService {
  3. @Autowired
  4. private UserDao userDao;
  5. public User queryUser(int id){
  6. return userDao.getUserById(id);
  7. }
  8. public List<User> queryUser2(int age){
  9. return userDao.getUserByAge(age);
  10. }
  11. }
  12. /*传递多个参数我们可以用 Map 来实现
  13. public List<User> queryUser4(Integer age, Integer start, Integer move){
  14. Map<String,Object> hashMap=new HashMap<>();
  15. hashMap.put("age",age);
  16. hashMap.put("start",start);
  17. hashMap.put("move",move);
  18. return userDao.selectById4(hashMap);
  19. }
  20. */

9.编写Controller

在 controller 目录中新建 UserController 类

这里我们使用 Restful 风格,直接返回数据。

使用 @Autowired 注解自动装配 UserService。编写接口为 UserService 传输数据

  1. @RestController
  2. public class UserController {
  3. @Autowired
  4. private UserService userService;
  5. @GetMapping("/getUser")
  6. public User getUser(@RequestParam("id") int id){
  7. return userService.queryUser(id);
  8. }
  9. @GetMapping("/getUser2")
  10. public List<User> getUser2(@RequestParam("age") int age){
  11. return userService.queryUser2(age);
  12. }
  13. }

10.运行项目

运行 SpringBoot 项目,我们在浏览器的地址栏中输入:

  1. localhost:8081/getUser?id=1
  2. localhost:8081/getUser2?age=20
  3. 12

即可看到返回了 id=1 和 age=20 的用户的 JSON 数据。因为这里是直接在地址栏输入参数和值,是采用 get 方式传输的,所以必须使用 GetMapping

3.Springboot整合mybaties - 图8

3.Springboot整合mybaties - 图9

到这一步,整个的后台访问流程就全部打通了,大家仔细理解其中的逻辑,多多揣摩。

参考文章

Mybatis官方文档

Springboot与MyBatis简单整合

spring boot框架mybatis.mapper-locations配置问题详解

MySQL驱动和时区设置

SpringBoot整合Mybatis完整详细版

mybatis返回值类型及正确使用resultType和resultMap

Mybatis实现数据持久化的三种方式