007 Spring Boot 整合 MyBatis

到目前为止,我们已经可以搭建一个 Rest API 服务了:

  • Druid 作为数据源和数据库连接池;
  • 使用 JdbcTemplate 作为数据库的操作工具。

这篇,我们再来整合 MyBatis 作为我们框架的数据库持久层。

1. MyBatis 简介

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。

MyBatis 本是Apache的一个开源项目 iBatis ,2010年这个项目由 Apache Software Foundation 迁移到了Google Code,并且改名为 MyBatis ,三年之后,MyBatis 于 2013年11月迁移到 Github,最终一直扎根于 Github,并开枝散叶,发展壮大。

具体更多的对 MyBatis 我们就不去介绍了,我们依然采用“所需”的开发原则,来讲述具体如何在项目中使用 MyBatis,详细的介绍可以参考 MyBatis中文官网 (请经常翻阅官网)

2. 准备好数据库

数据库表,依然用我们之前的,见:005 Spring Boot 使用 JdbcTemplate 操作数据库, 这里我们就不重复阐述。

3. 添加依赖

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

4. 创建实体类

package com.jdz.entity;

import lombok.Data;

@Data
public class User {
    private Integer uid;
    private String name;
    private Integer age;
    private String addr;
}

  1. 这里我们使用了 Lombok 的 @Data 注解。关于 Lombok 见: Lombok

5. 创建 Mapper 接口类

package com.jdz.mapper;

import com.jdz.entity.User;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface UserMapper {
    public boolean doCreate(User user);

    public boolean doDelByUid(Integer uid);

    public boolean doUpdate(User user);

    public User findByUid(Integer uid);

    public List<User> findAll();
}

注意:

  1. UserMapper 增加 @Mapper

6. 创建 Mapper 对应的 xml 文件

创建 src/main/resources/mapper/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.jdz.mapper.UserMapper">
    <resultMap id="BaseResultMap" type="User">
        <id column="uid" property="uid" />
        <result column="name" property="name" />
        <result column="age" property="age" />
        <result column="addr" property="addr" />
    </resultMap>

    <sql id="Base_Column_List">
        uid, name, age, addr
    </sql>

    <insert id="doCreate">
        insert into jdz_user(name, age, addr) values (#{name}, #{age}, #{addr})
    </insert>

    <update id="doUpdate" parameterType="User">
        update jdz_user
        <set>
            <if test="name != null"> name = #{name}, </if>
            <if test="age != null"> age = #{age}, </if>
            <if test="addr != null"> addr = #{addr} </if>
        </set>
        where uid = #{uid}
    </update>

    <delete id="doDelByUid">
        delete from jdz_user where uid=#{uid}
    </delete>

    <select id="findByUid" resultType="User">
        select * from jdz_user where uid=#{uid}
    </select>

    <select id="findAll" resultMap="BaseResultMap">
        select * from jdz_user
    </select>
</mapper>

注:

  1. namespace 的值必须与对应的 mapper 接口的完全限定名一致;
  2. <select> <insert> <delete> 中的 id 必须与 mapper 接口中的方法名一致;

7. 创建配置文件

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/app_test?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC&characterEncoding=utf8
    username: root
    password:
    type: com.alibaba.druid.pool.DruidDataSource

mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml  # 指定 mapper.xml 的位置
  #扫描实体类的位置,在此处指明扫描实体类的包,在 mapper.xml 中就可以不写实体类的全路径名
  type-aliases-package: com.jdz.entity

logging:
  file:
    path: logs/

注:

  1. 这里配置文件使用的是 application.yml 格式,application.properties 相应的配置也是一样的;
  2. mybatis.mapper-locations 这是 mapper 对应的 xml 文件位置,* 是通配符
  3. type-aliases-packag 是实体类所在的包路径

8. 创建 service

package com.jdz.service;

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

import java.util.List;

@Service
public class UserService {
    @Autowired
    UserMapper userMapper;

    public boolean addUser(User user){
        return userMapper.doCreate(user);
    }

    public boolean updateUser(User user) {
        return userMapper.doUpdate(user);
    }

    public boolean delUser(Integer uid) {
        return userMapper.doDelByUid(uid);
    }

    public User getInfo(Integer uid) {
        return userMapper.findByUid(uid);
    }

    public List<User> getAll(){
        return userMapper.findAll();
    }
}

注:

  1. UserService 使用 @Service 注解
  2. userMapper 使用 @Autowired 注解

9. 创建 controller

package com.jdz.controller;

import com.jdz.entity.User;
import com.jdz.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("/user/add")
    public String addUser(User user) {
        userService.addUser(user);
        return "ok";
    }

    @RequestMapping("/user/save")
    public boolean saveUser(User user) {
        return userService.updateUser(user);
    }

    @RequestMapping("/user/del")
    public String delUser(Integer uid) {
        userService.delUser(uid);
        return "ok";
    }

    @RequestMapping("/user/info")
    public User info(Integer uid) {
        return userService.getInfo(uid);
    }

    @RequestMapping("/user/list")
    public List<User> userList() {
        return userService.getAll();
    }
}

完整的目录接口:

javaapp
├─pom.xml
├─src
|  ├─main
|  |  ├─resources
|  |  |     ├─application.yml
|  |  |     ├─mapper
|  |  |     |   └UserMapper.xml
|  |  ├─java
|  |  |  ├─com
|  |  |  |  ├─jdz
|  |  |  |  |  ├─App.java
|  |  |  |  |  ├─service
|  |  |  |  |  |    └UserService.java
|  |  |  |  |  ├─mapper
|  |  |  |  |  |   └UserMapper.java
|  |  |  |  |  ├─entity
|  |  |  |  |  |   └User.java
|  |  |  |  |  ├─controller
|  |  |  |  |  |     └UserController.java
|  |  |  |  |  ├─config
|  |  |  |  |  |   ├─MyDuridConfig.java
|  |  |  |  |  |   └MyFastJsonConfig.java

到此,一个整合了 MyBatis 的 Spring Boot 就完成了,启动程序,并访问相应的接口后,就有相应的数据返回。

说说我个人在使用 MyBatis 上的体会:

  1. MyBatis 从某种层面上,是把与数据库相关的 SQL 语句与 java 的业务代码抽离出来,放进了 xml 里面,使繁杂的 SQL 相关的操作与业务代码解耦,在任务分块方面也更清晰;
  2. java 程序员只关注具体的逻辑代码的实现,而不需要去关注具体的数据是如何处理的;
  3. 数据库相关的开发人员,只关注 SQL 语句的实现和优化以及数据的提供;
  4. 同时,如果底层的数据(或数据库)有变更,都不会影响代码的处理;i
    缺陷就是要维护和处理 xml 格式的 SQL,这写久了SQL嵌入代码里程序员来说,会有些不适应。

源码:

发表评论