文章目录

  • 一、整合Mybatis
    • 1.搭建数据库环境
    • 2.基于注解整合Mybatis
      • (1)创建项目
      • (2)具体代码实现
      • (3)测试
    • 3.基于xml整合Mybatis
    • 4.Mybatis的动态SQL
      • (1)if
      • (2)choose
      • (3)trim、where、set
      • (4)foreach
      • (5)bind
  • 二、整合 Mybatis 多数据源
    • 1.数据库环境搭建
    • 2.实体类
    • 3.在application.yml配置数据源
    • 4.配置类配置数据源
    • 5.配置类配置 Mybatis
    • 6.编写 Dao接口和 SQL 映射文件
    • 7.编写controller
    • 8.测试
  • 三、整合分页插件 PageHelper
    • 1.搭建数据库、项目配置
    • 2.添加依赖
    • 3.在代码中使用PageHelper
      • (1)entity
      • (2)dao
      • (3)controller
      • (4)测试
      • (5)返回类PageInfo
  • 四、整合 Mybatis-Plus
    • 1.数据库搭建、配置
    • 2.添加依赖
    • 3.代码实现
      • (1)entity
      • (2)dao
      • (3)service
      • (4)config
        • 配置分页插件
        • 条件构造器
      • (5)controller
    • 4.测试

Mybatis在整个体系中的作用是负责连接并访问数据库层。搞过开发的同学都知道,没有数据库的项目一无是处,所以Mybatis的学习是很有必要的。

准备工作:

  • 数据库:在进入正式学习前,先确保Mysql已经在电脑上安装好了,最好再安装一个可视化管理工具Navicat Premium for mysql。当然,你还要会mysql的语法和基本操作等。
  • spring boot项目创建以及一些前置知识:可以看我上一篇博客

一、整合Mybatis

整合Mybatis可以基于注解,也可以基于xml文件,二者的区别:

1.搭建数据库环境

新建一个数据库boot_demo,然后执行以下sql语句:

-- 创建表USE `boot_demo`;DROP TABLE IF EXISTS `tb_user`;CREATE TABLE `tb_user`  (  `user_id` int(11) NOT NULL ,  `user_name` varchar(20)  DEFAULT NULL,  `user_age` int(11)  DEFAULT NULL,   PRIMARY KEY (`user_id`)) ENGINE = InnoDB;-- 插入数据REPLACE INTO `tb_user` (`user_id`, `user_name`, `user_age`) VALUES ('100', 'test01', '100');

2.基于注解整合Mybatis

(1)创建项目

项目信息填写如下:

选择初始依赖:

完善目录结构:

在main/java/com/tracy/mybatisdemo下依次新建 entity 、dao 和 controller 文件夹。一般来说,应该再创建一个service包,前端调用controller接口,controller调用service,service再调用dao,但这章为了简化操作省去了service部分,到后面项目实战的时候我会创建更完善的目录结构。

(2)具体代码实现

  • 实体类User:

在entity包下创建User类,代码如下:

package com.tracy.mybatisdemo.entity;import lombok.Data;//此注解来源于Lombok插件,运行时会自动为类添加 Getter、Setter 、有参构造、toString 、equals 和 hashCode 方法@Datapublic class User {    private Integer userId;    private String userName;    private Integer userAge;}
  • 持久层UserDao接口:

在dao包下创建UserDao接口:

package com.tracy.mybatisdemo.dao;import com.tracy.mybatisdemo.entity.User;import org.apache.ibatis.annotations.*;import org.springframework.stereotype.Repository;import java.util.List;@Repositorypublic interface UserDao {    @Select("select user_id,user_name,user_age from tb_user")    List<User> findAll();    @Select("select user_id,user_name,user_age from tb_user where user_id = #{userId}")    User findById(Integer userId);    @Insert("insert into tb_user (user_id,user_name,user_age) values (#{userId},#{userName},#{userAge})")    Integer insert(User user);    @Update("update tb_user set user_name=#{userName},user_age=#{userAge} where user_id = #{userId}")    Integer update(User user);    @Delete("delete from tb_user where user_id=#{userId}")    Integer delete(Integer userId);}
  • 配置包扫描:

为了使每个dao接口都被扫描到,可以在每个dao接口上加上@Mapper注解,但当dao接口比较多的时候,推荐直接在启动类上通过注解@MapperScan("com.tracy.mybatisdemo.dao")的形式扫描整个dao包:

@SpringBootApplication@MapperScan("com.tracy.mybatisdemo.dao")public class MybatisDemoApplication {    public static void main(String[] args) {        SpringApplication.run(MybatisDemoApplication.class, args);    }}
  • 控制层UserController类:

在controller包下创建UserController类:

package com.tracy.mybatisdemo.controller;import com.tracy.mybatisdemo.dao.UserDao;import com.tracy.mybatisdemo.entity.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import java.util.List;@RestController@RequestMapping("/user")public class UserController {    @Autowired    private UserDao userDao;    @GetMapping("/findAll")    public List<User> findAll(){        return userDao.findAll();    }    @GetMapping("/findById")    public User findById(Integer userId){        return userDao.findById(userId);    }    @PostMapping("/insert")    public String insert(User user){        userDao.insert(user);        return "插入成功后的数据为" + userDao.findById(user.getUserId());    }    @PutMapping("/update")    public String update(User user){        userDao.update(user);        return "更新成功后的数据为" + userDao.findById(user.getUserId());    }    @DeleteMapping("/delete")    public String delete(Integer userId){        userDao.delete(userId);        return "删除成功的id" + userId;    }}
  • 添加数据库配置:

在application.yml中添加以下配置:

# 数据源spring:  datasource:    driver-class-name: com.mysql.cj.jdbc.Driver    url: jdbc:mysql://localhost:3306/boot_demo" />

  • 测试 localhost:8080/user/findById GET

  • 测试 localhost:8080/user/insert POST

  • 测试 localhost:8080/user/update PUT

  • 测试 localhost:8080/user/delete DELETE

成功!

3.基于xml整合Mybatis

基于注解的Mybatis使用只能应付一些比较简单的数据库查询语句,虽然省事,但在一定程度上也丧失了灵活性,因此,有必要学习一下基于xml整合Mybatis。

  • 首先,请先删除UserDao接口中每个方法上的注解语句:
package com.tracy.mybatisdemo.dao;import com.tracy.mybatisdemo.entity.User;import org.springframework.stereotype.Repository;import java.util.List;@Repositorypublic interface UserDao {    List<User> findAll();        User findById(Integer userId);    Integer insert(User user);    Integer update(User user);    Integer delete(Integer userId);}
  • 添加xml映射文件:

在resources目录下创建目录mapper,仔仔mapper目录下创建UserMapper.xml文件:

注意 mapper namespace=“com.tracy.mybatisdemo.dao.UserDao” 一定要与dao包下的接口对应起来。

<" />

三、整合分页插件 PageHelper

官方文档参考: 这里
博客参考: 这里

Mybatis 内部其实提供了分页功能。实现原理是将数据一次性查询到内存中,再进行切分,从而实现分页,是一种逻辑分页方式。当数据量过大的时候,一次性读取数据对数据库和程序的性能都有很大的影响,因此这种方式不推荐使用。

而PageHelper 插件是一种物理分页方式。其实现原理是在执行查询的时候,获取页面参数,通过拦截器在 SQL 语句中添加分页参数生成分页 SQL, 最终实现分页查询。

1.搭建数据库、项目配置

在mysql中创建数据库page,然后执行:

USE `page`;DROP TABLE IF EXISTS `tb_user`;CREATE TABLE `tb_user`  (  `user_id` int(11) NOT NULL AUTO_INCREMENT,  `user_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,  `user_age` int(11) NULL DEFAULT NULL,  PRIMARY KEY (`user_id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;-- ------------------------------ Records of tb_user-- ----------------------------INSERT INTO `tb_user` VALUES (1, 'user01', 18);INSERT INTO `tb_user` VALUES (2, 'user02', 19);INSERT INTO `tb_user` VALUES (3, 'user03', 18);INSERT INTO `tb_user` VALUES (4, 'user04', 19);INSERT INTO `tb_user` VALUES (5, 'user05', 18);INSERT INTO `tb_user` VALUES (6, 'user06', 19);INSERT INTO `tb_user` VALUES (7, 'user07', 18);INSERT INTO `tb_user` VALUES (8, 'user08', 19);INSERT INTO `tb_user` VALUES (9, 'user09', 18);INSERT INTO `tb_user` VALUES (10, 'user10', 19);INSERT INTO `tb_user` VALUES (11, 'user11', 18);INSERT INTO `tb_user` VALUES (12, 'user12', 19);INSERT INTO `tb_user` VALUES (13, 'user13', 18);INSERT INTO `tb_user` VALUES (14, 'user14', 19);INSERT INTO `tb_user` VALUES (15, 'user15', 18);INSERT INTO `tb_user` VALUES (16, 'user16', 19);INSERT INTO `tb_user` VALUES (17, 'user17', 18);INSERT INTO `tb_user` VALUES (18, 'user18', 19);INSERT INTO `tb_user` VALUES (19, 'user19', 18);INSERT INTO `tb_user` VALUES (20, 'user20', 19);

在启动类上配置包扫描:

@MapperScan("com.tracy.mybatisdemo.dao")

在application.yml中配置:

# 数据源spring:  datasource:    driver-class-name: com.mysql.cj.jdbc.Driver    url: jdbc:mysql://localhost:3306/page" />

Wrapper是一个条件构造器,作用就是帮我们写 SQL 语句中 where 字段后的那部分内容。

若通用方法无法满足业务需求,你可以在 Mapper 接口中添加自定义方法,同时在 XML 中添加 SQL ,与传统 Mybatis 的写法一致。

(3)service

  • 接口:

在service包下创建UserService接口:

package com.tracy.mybatisdemo.service;import com.baomidou.mybatisplus.extension.service.IService;import com.tracy.mybatisdemo.entity.User;public interface UserService extends IService<User> {}

继承 MP 提供的 IService 接口:

为了避免和 Mapper 接口中的方法混淆,Service 层中的方法命名和 Mapper 有些区别。

增加:insert → save
删除:delete → remove
更新:udpate → update
查询: select → get,list

  • 实现:

在service包下创建UserServiceImpl类:

package com.tracy.mybatisdemo.service;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import com.tracy.mybatisdemo.dao.UserDao;import com.tracy.mybatisdemo.entity.User;import org.springframework.stereotype.Service;@Servicepublic class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService{}

在 ServiceImpl 类中,它会获取泛型参数中的 UserDao 接口和 User 类,利用这两者来封装 Service 层的操作:

(4)config

配置分页插件

在config包下新建 MybatisPlusConfig配置类:

package com.tracy.mybatisdemo.config;import com.baomidou.mybatisplus.annotation.DbType;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;import org.mybatis.spring.annotation.MapperScan;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configuration@MapperScan("com.tracy.mybatisdemo.dao") //配置dao包扫描public class MybatisPlusConfig {    /**     * 添加分页插件     */    @Bean    public MybatisPlusInterceptor mybatisPlusInterceptor() {        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();        // 新的分页插件,一缓和二缓遵循mybatis的规则        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));        return interceptor;    }}

分页插件配置完成后,通过如下方式便可进行分页:

 Page<User> userPage = new Page<>();// 设置当前页userPage.setCurrent(pageNum);// 设置页面大小userPage.setSize(pageSize);// 方式1.无条件分页查询Page<User> page = userService.page(userPage);// 方式2.条件分页查询Page<User> pageByWrapper = userService.page(userPage,new LambdaQueryWrapper<User>() .isNotNull(User::getUserName));

条件构造器

针对复杂 SQL ,可以采用条件构造器构造条件。

  • QueryWapper

针对 QueryWapper ,它使用数据库 Column 来构造条件,在编译期间无法检查出错误。

// 构建一个条件构造器QueryWrapper<User> queryWrapper = new QueryWrapper<>();// 查询名字不为空且年龄大于18的用户,使用数据库字段queryWrapper    .isNotNull("user_name")    .ge("user_age",18);// 条件查询List<User> users = userService.list(queryWrapper);
  • LambdaQueryWrapper

针对 LambdaQueryWrapper ,它使用 POJO 对象字段来构造条件,可以在程序编译的时候就能发现错误。

// 构建一个条件构造器LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();// 查询名字不为空且年龄大于18的用户,使用实体类字段lambdaWrapper        .isNotNull(User::getUserName)        .ge(User::getUserAge,18);// 条件查询List<User> users = userService.list(lambdaWrapper);

更多用法可参考博客:这里

(5)controller

在controller包下创建:

package com.tracy.mybatisdemo.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;import com.tracy.mybatisdemo.entity.User;import com.tracy.mybatisdemo.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import java.util.List;@RestController@RequestMapping("/user")public class UserController {    @Autowired    public UserService userService;    /**     * 查询所有-list()方法     */    @GetMapping("/list")    public String list() {        List<User> list = userService.list();        return list.toString();    }    /**     * 根据年龄查询用户     */    @GetMapping("/queryByAge")    public String queryByAge(Integer age) {        // 查询名字不为空且年龄大于给定年龄的用户        // 条件查询方式1:使用QueryWrapper,使用数据库字段        List<User> list = userService.list(new QueryWrapper<User>().isNotNull("user_name").ge("user_age", age));        // 条件查询方式2:使用LambdaQueryWrapper,使用POJO字段        List<User> list1 = userService                .list(new LambdaQueryWrapper<User>().isNotNull(User::getUserName).ge(User::getUserAge, age));        // 条件查询方式3:使用链式query,使用数据库字段        List<User> list2 = userService.query().isNotNull("user_name").ge("user_age", age).list();        // 条件查询方式4:使用链式lambdaquery,使用POJO字段        List<User> list3 = userService.lambdaQuery().isNotNull(User::getUserName).ge(User::getUserAge, age).list();        // 只返回其中一种方式的查询结果        return list.toString();    }    /**     * 添加用户-save()     */    @PostMapping("/save")    public boolean save(String userName, Integer userAge) {        User user = new User();        user.setUserName(userName);        user.setUserAge(userAge);        return userService.save(user);    }    /**     * 删除用户-removeById()     */    @DeleteMapping("/remove")    public boolean remove(Integer userId) {        return userService.removeById(userId);    }    /**     * 更新用户-updateById()     */    @PutMapping("/update")    public boolean update(User user) {        // 注意,参数是一个对象        return userService.updateById(user);    }    /**     * 分页查询     */    @GetMapping("/page")    public Page<User> page(Integer pageNum, Integer pageSize) {        Page<User> userPage = new Page<>();        // 设置当前页        userPage.setCurrent(pageNum);        // 设置页面大小        userPage.setSize(pageSize);        // 方式1.无条件分页查询        Page<User> page = userService.page(userPage);        // 方式2.条件分页查询        Page<User> pageByWrapper = userService.page(userPage,                new LambdaQueryWrapper<User>().isNotNull(User::getUserName));        return page;    }}

4.测试

运行项目后请自行在postman中测试每个方法,不再赘述。