SpringBoot 整合 MyBatis

SpringBoot 整合 MyBatis

MyBatis 简介

MyBatis 官方所述:

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Ordinary Java Objects,简单 Java 对象)为数据库中的记录。

MyBatis 的优势

MyBatis 作为一款优秀的持久层框架,具有如下优点:

  1. 小巧并且简单易学;
  2. 相比于 JDBC 减少了大量冗余的代码;
  3. 将 SQL 语句与程序代码进行分离,降低了耦合,便于管理;
  4. 提供 XML 标签,支持编写动态 SQL 语句;
  5. 提供映射标签,支持 Java 对象与数据库 ORM 字段的映射关系。

MyBatis 的缺点

  1. SQL 语句编写工作量较大,尤其是字段和关联表比较多时。
  2. SQL 语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

MyBatis 实践

创建 SpringBoot 项目,整合 MyBatis,实现简单 CRUD。

1. 引入依赖

POM 文件如下:



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.5.6
         
    
    com.example
    springboot-mybatis
    0.0.1-SNAPSHOT
    springboot-mybatis
    Demo project for Spring Boot
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            mysql
            mysql-connector-java
            runtime
        

        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.2.0
        

        
            org.springframework.boot
            spring-boot-starter-jdbc
        

        
            org.springframework.boot
            spring-boot-devtools
            runtime
            true
        

        
            org.projectlombok
            lombok
            true
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    
                        
                            org.projectlombok
                            lombok
                        
                    
                
            
        
    

2. 配置 MySQL 和 MyBatis

application.yml 配置文件如下:

# 配置MySQL
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

# 配置MyBatis
mybatis:
  mapper-locations: classpath:mapper/*
  type-aliases-package: com.example.entity
  configuration:
    map-underscore-to-camel-case: true

上述配置文件中,mapper-locations 用来指定 mapper 文件的路径;type-aliases-package 用来设置别名,它的作用是让 MyBatis 扫描我们自定义的实体类,即 'com.example.entity' 包下的所有类,这些类都会被注册到 TYPE_ALIASES 容器,这样在 mapper 文件中可以直接使用非限定类名来作为它的别名,如 'com.example.entity.User' 可使用别名 'User' 代替;map-underscore-to-camel-case 为 true 时表示开启驼峰命名自动映射,如将 user_name 映射为 userName。

3. 编写实体类

本文以 User 类为例:

package com.example.entity;

import lombok.Data;

import java.util.Date;

/**
 * @Author john
 * @Date 2021/11/14
 */
@Data
public class User {

    private long id;

    private String userName;

    private int age;

    private String address;

    private Date createTime;

    private Date updateTime;
}

User 类中封装了用户的 id、姓名、年龄、地址、创建时间以及修改时间等信息。

4. 编写 Mapper 类和 mapper 文件

首先编写 UserMapper 接口:

package com.example.mapper;

import com.example.entity.User;

/**
 * @Author john
 * @Date 2021/11/16
 */
public interface UserMapper {
    
    void insertUser(User user);
    
    User findUserById(long id);
}

接口中定义了两个方法,insertUser 用来向数据表中插入一条记录;findUserById 用来通过 id 查询 User。

上述操作完成后,我们在 resources 文件夹中创建 mapper/user-mapper.xml 文件(文件路径在上述配置文件 application.yml 中设置)。mapper 文件的内容如下:






    
        user_name, age, address, gmt_create, gmt_modified
    

    
        id, user_name, age, address, gmt_create, gmt_modified
    

    
        
        
        
        
        
        
    

    

    
        insert into user ()
        values(#{userName}, #{age}, #{address}, UTC_TIMESTAMP(), UTC_TIMESTAMP())
    

mapper 文件需要与 Mapper 接口对应:Mapper 接口的全限定名,对应 mapper 文件的 namespace 值;接口的方法名,对应 mapper 文件 Statement 的 id 值;方法的参数,就是传递给 SQL 的参数;方法的返回值就是 SQL 返回的数据。

parameterType 和 resultType(本实验中未使用)分别用来指定参数和返回值的类型,因为我们在配置文件中启用了别名,所以 parameterType 和 resultType 可以直接设置为 'User' 或 'user',而非全限定名 'com.example.entity.User'。关于别名的设置还有其他几种方法,这个我们在后文讨论。

MyBatis中 别名不区分大小写

mapper 文件中还有一个关键标签 resultMap,resultMap 主要用来创建自定义的映射关系。以查询为例,MyBatis 的映射规则是:根据查询到的列名找到 POJO 对应的属性名,然后调用该属性的 setter 方法进行赋值。本实验中,user 表的 id 会自动映射为 User 对象的 id,因为字段名和属性名是完全一致的;user 表的 user_name 也会自动映射为 User 对象的 userName,因为我们开启了驼峰式命名映射。但是 gmt_create 不会映射到 createTime,因为字段名和属性名既不完全一致,也不符合驼峰式命名映射的规则。所以这里我们使用 resultMap 来创建新的映射关系,将 gmt_create 和 gmt_modified 分别映射到 createTime 和 updateTime,然后再将 resultType 替换为 resultMap(如果不需要自定义映射,本实验中的 resultMap='UserMap' 可替换为 resultType='User')。resultMap 还有一些其他功能,关于 resultMap 的使用方法可以参考我的另一篇博客

另外,本实验中,resultMap 标签也可以定义为:


    
    

因为其他字段会自动映射,不需要额外书写。

TODO

5. 编写 Service

创建 UserService:

package com.example.service;

import com.example.entity.User;
import com.example.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Author john
 * @Date 2021/11/16
 */
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public void insertUser(User user) {
        userMapper.insertUser(user);
    }

    public User findUserById(long id) {
        return userMapper.findUserById(id);
    }
}

在 UserService 中注入 UserMapper 对象,并调用 UserMapper 的 insertUser()/findUserById() 方法来添加/查询 User。

为了能够正常注入 UserMapper 对象,我们还需要再启动类上添加 @MapperScan 注解,用来指定 Mapper 接口的路径:

package com.example;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.example.mapper")
public class SpringbootMybatisApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootMybatisApplication.class, args);
    }

}

上述代码中我们指定 Mapper 接口的路径为 'com.example.mapper' 包,该包下的所有 Mapper 接口都会被扫描。

除了在启动类上添加 @MapperScan 注解外,还可以在 Mapper 接口上直接添加 @Mapper 注解,这种方法相对比较麻烦,因为实际中我们可能会有多个 Mapper 接口,这样就需要添加多个注解。

6. 创建 user 表

user 表字段设计如下(设置 id 自增):

SpringBoot 整合 MyBatis_第1张图片

7. 测试

编写测试接口:

package com.example;

import com.example.entity.User;
import com.example.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class SpringbootMybatisApplicationTests {

    @Autowired
    private UserService service;

    @Test
    public void addUser(){
        User user = new User();
        user.setUserName("John");
        user.setAge(24);
        user.setAddress("BUPT");
        service.insertUser(user);
    }

    @Test
    public void findUser(){
        System.out.println(service.findUserById(1));
    }
}

首先执行 addUser() 方法,执行成功后查询数据表,得到如下信息:

查询结果

然后执行 findUser() 方法,执行结果如下:

findUser() 方法执行结果

至此,SpringBoot 整合 MyBatis 测试成功!

8. MyBatis 设置别名的其他方式

方式一:在配置文件 application.yml 中添加配置。

map-underscore-to-camel-case: true

本实验中就使用此种方式(简单方便),默认情况下实体类的别名为其类名(严格来说是首字母小写的非限定类名,但别名不区分大小写,所以 User、user、uSer 的效果都是相同的),可以自定义别名吗,比如设置别名为 'hello'?当然可以,方式二介绍完毕后我们再讨论。

方式二:使用 MyBatis 的配置文件 filename.xml。

首先在 yml 文件中设置 MyBatis 配置文件的路径:

# 配置MyBatis
mybatis:
  mapper-locations: classpath:mapper/*
  type-aliases-package: com.example.entity
  config-location: classpath:mybatis/mybatis-config.xml #MyBatis配置文件

然后在 resource 文件夹下创建 MyBatis 的配置文件 mapper/mybatis-config.xml(路径和文件名在 config-location 中设置),配置文件内容如下:






    
        
    

    
        
    

setting 标签中可以设置开启驼峰命名映射,其效果与在 yml 文件中配置 map-underscore-to-camel-case: true 是相同的。

typeAliases 标签中,设置 package 可以让 MyBatis 扫描指定包下的实体类,其效果与在 yml 文件中配置 type-aliases-package: com.example.entity 是相同的。

方式一和方式二实现效果是相同的,本实验中实体类 'com.example.entity.User' 可使用其别名 'User' 或 'user' 代替,如果希望使用其他别名,可以搭配 @Alias 注解一起使用,即在实体类上添加该注解:

package com.example.entity;

import lombok.Data;
import org.apache.ibatis.type.Alias;

import java.util.Date;

/**
 * @Author john
 * @Date 2021/11/14
 */
@Data
@Alias("hello")
public class User {

    private long id;

    private String userName;

    private int age;

    private String address;

    private Date createTime;

    private Date updateTime;
}

这里我们设置 User 类的别名为 'hello',这样在 user-mapper.xml 文件中,将 type、parameterType 以及 resultType 替换为 'hello',程序仍可正常运行,但此时如果继续使用 'User' 或者 'user',则会报别名解析错误,因为 @Alias 注解会使默认的别名变得无效(方式一和方式二都可搭配 @Alias 注解一起使用)。

方式三:在 MyBatis 的配置文件中自定义别名。

与方式二相似,只不过这次我们不使用 package 标签,而是使用 typeAlias 标签:






    
        
    

    
        

    

使用 typeAlias 标签可以帮助我们 DIY 别名,且不需要使用注解 @Alias。使用此种方式定义别名时,如果有多个实体类,那么就需要为每个类都设置一个别名,较为繁琐。

值得注意的是,如果我们已经实现了方式一或方式二,那么我们仍可以使用方式三添加别名,也就是说如果没有配置 @Alias 注解,那么 User 类的别名可以是默认的 'User' 或方式三 DIY 的别名;如果配置了 @Alias 注解,那么 User 类的别名可以是 @Alias 指定的别名或方式三 DIY 的别名。

欢迎批评指正!!!

你可能感兴趣的:(SpringBoot 整合 MyBatis)