关于java:SpringBoot-整合-MyBatis

39次阅读

共计 9798 个字符,预计需要花费 25 分钟才能阅读完成。

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 文件如下:

<?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.5.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>springboot-mybatis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-mybatis</name>
    <description>Demo project for Spring Boot</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>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

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 文件的内容如下:

<?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.mapper.UserMapper">

    <sql id="insertFields">
        user_name, age, address, gmt_create, gmt_modified
    </sql>

    <sql id="selectFields">
        id, user_name, age, address, gmt_create, gmt_modified
    </sql>

    <resultMap id="UserMap" type="User">
        <result column="id" jdbcType="INTEGER" property="id"/>
        <result column="user_name" jdbcType="VARCHAR" property="userName"/>
        <result column="age" jdbcType="INTEGER" property="age"/>
        <result column="address" jdbcType="VARCHAR" property="address"/>
        <result column="gmt_create" jdbcType="DATE" property="createTime" />
        <result column="gmt_modified" jdbcType="DATE" property="updateTime" />
    </resultMap>

    <select id="findUserById" parameterType="Long" resultMap="UserMap">
        select
        <include refid="selectFields"></include>
        from user
        where id = #{id}
    </select>

    <insert id="insertUser" parameterType="User" keyProperty="id">
        insert into user (<include refid="insertFields"></include>)
        values(#{userName}, #{age}, #{address}, UTC_TIMESTAMP(), UTC_TIMESTAMP())
    </insert>

</mapper>

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 标签也能够定义为:

<resultMap id="UserMap" type="User">
    <result column="gmt_create" jdbcType="DATE" property="createTime" />
    <result column="gmt_modified" jdbcType="DATE" property="updateTime" />
</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 自增):

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() 办法,执行后果如下:

至此,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 中设置),配置文件内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <typeAliases>
        <package name="com.example.entity"/>
    </typeAliases>

</configuration>

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 标签:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <typeAliases>
        <typeAlias type="com.example.entity.User" alias="User"/>
<!--        <package name="com.example.entity"/>-->
    </typeAliases>

</configuration>

应用 typeAlias 标签能够帮忙咱们 DIY 别名,且不须要应用注解 @Alias。应用此种形式定义别名时,如果有多个实体类,那么就须要为每个类都设置一个别名,较为繁琐。

值得注意的是,如果咱们曾经实现了形式一或形式二,那么咱们仍能够应用形式三增加别名,也就是说如果没有配置 @Alias 注解,那么 User 类的别名能够是默认的 ‘User’ 或形式三 DIY 的别名;如果配置了 @Alias 注解,那么 User 类的别名能够是 @Alias 指定的别名或形式三 DIY 的别名。

欢送批评指正!!!

正文完
 0