文章目录

  • 一、整合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的学习是很有必要的。提供本文章的demo仓库。

准备工作:

  • 数据库:在进入正式学习前,先确保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 方法
@Data
public 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;@Repository
public 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 {@Autowiredprivate 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.Driverurl: jdbc:mysql://localhost:3306/boot_demo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8username: rootpassword: 你的密码# Mybatis配置
# 开启驼峰式命名规则自动转换
mybatis:configuration:map-underscore-to-camel-case: true

(3)测试

测试工具我使用的是postman,怎么安装和使用可以网上百度一下。

  • 测试 localhost:8080/user/findAll GET

  • 测试 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;@Repository
public 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包下的接口对应起来。

<?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.tracy.mybatisdemo.dao.UserDao"><!--查询所有用户--><select id="findAll" resultType="user">select * from tb_user</select><!--根据id查询单个用户--><select id="findById" parameterType="int" resultType="user">select * from tb_user where user_id = #{userId}</select><!--插入用户--><insert id="insert" parameterType="user">insert into tb_user (user_id,user_name,user_age) values (#{userId},#{userName},#{userAge})</insert><!--更新用户信息--><update id="update" parameterType="map">update tb_user set user_name = #{userName}, user_age = #{userAge}where user_id = #{userId}</update><!--删除用户--><delete id="delete" parameterType="int">delete from tb_user where user_id = #{userId}</delete>
</mapper>
  • 添加Mybatis实体映射配置:

在application.yml配置文件中增加mybatis部分的配置:

# Mybatis配置
# 开启驼峰式命名规则自动转换
mybatis:configuration:map-underscore-to-camel-case: truetype-aliases-package: com.tracy.mybatisdemo.entitymapper-locations: classpath:mapper/*Mapper.xml

type-aliases-package: com.tracy.mybatisdemo.entity 表示将UserMapper.xml中的resultType与com.tracy.mybatisdemo.entity包下的实体类绑定起来,否则UserMapper.xml中的resultType需要写上完整的包名com.tracy.mybatisdemo.entity.user。
*mapper-locations: classpath:mapper/Mapper.xml 表示将dao路径下的各个接口与resources/mapper路径下的各个xml文件映射起来,classpath等价于resources目录。

  • 测试:

前面已经演示过了,url和过程都是一模一样的,请用postman或者别的测试工具自行测试吧。

4.Mybatis的动态SQL

(1)if

if 在 where 子句中做简单的条件判断。

我们以UserMapper.xml中的update方法的实现为例:

  • 原来的写法:

当我们调用这个接口时,必须把用户名、用户年龄参数都传入,也就是说我们必须修改每一个属性值。但是如果我们只想选择性地修改属性值呢,比如,有时候我们只想修改user_name,有时候又只想修改user_age。

    <!--更新用户信息--><update id="update" parameterType="map">update tb_user set user_name = #{userName}, user_age = #{userAge}where user_id = #{userId}</update>
  • 使用if进行动态SQL绑定:

我们为每个参数的传入加上一个if判断,test="user_name!=null"表明了它的判断条件,只有当该参数传入不为空时才进行修改,这就是一种动态绑定的策略。

    <!--更新用户信息--><update id="update" parameterType="map">update tb_user set user_id = #{userId}<if test="userName!=null">user_name = #{userName}</if><if test="userAge!=null">user_age = #{userAge}</if>where user_id = #{userId}</update>

(2)choose

相当于java语言中的Switch语句。

  • 仍以update方法为例:

每个when语句都是一个条件,第一个条件满足了就跳出choose语句,否则判断下一个when条件。如果所有的when条件都不满足,就直接选择otherwise中的条件。

    <!--更新用户信息--><update id="update" parameterType="map">update tb_user set<choose><when test="userName!=null">user_name = #{userName}</when><when test="userAge!=null">user_age = #{userAge}</when><otherwise>user_id = #{userId}</otherwise></choose>where user_id = #{userId}</update>

(3)trim、where、set

  • trim:

先来看看这个语句,如果两个if条件都不成立,那sql语句就会变成update tb_user set where user_id = #{userId},这就会导致语法上的错误:

    <!--更新用户信息--><update id="update" parameterType="map">update tb_user set <if test="userName!=null">user_name = #{userName}</if><if test="userAge!=null">user_age = #{userAge}</if>where user_id = #{userId}</update>

使用trim语句,prefix表示整个trim语句的前缀是set,suffixOverrides属性表示消除每个子句末尾可能会带来的冗余符号(不冗余则不消除),prefixOverrides消除的是子句头部的冗余:

    <!--更新用户信息--><update id="update" parameterType="map">update tb_user<trim prefix="set" suffixOverrides=","><if test="userName!=null">user_name = #{userName},</if><if test="userAge!=null">user_age = #{userAge},</if></trim>where user_id = #{userId}</update>
  • 可使用专门的set语句:
    <!--更新用户信息--><update id="update" parameterType="map">update tb_user<set><if test="userName!=null">user_name = #{userName}</if><if test="userAge!=null">user_age = #{userAge}</if><if test="userId!=null">user_id = #{userId}</if></set>where user_id = #{userId}</update>
  • 可使用专门的where语句:

在where元素中至少有一个if子句成立;where元素能智能地处理 and 和 or 条件。

<!--更新用户信息--><update id="update" parameterType="map">update tb_user<trim prefix="set" suffixOverrides=","><if test="userName!=null">user_name = #{userName},</if><if test="userAge!=null">user_age = #{userAge},</if><if test="userId!=null">user_id = #{userId},</if></trim><where><if test="userId!=null">user_id = #{userId},</if></where>

(4)foreach

当需要对一个集合进行遍历时,foreach 元素是很有用的,尤其在 in 语句查询时特别有用。

这部分看这两篇博客:1、2

(5)bind

这部分看这篇:这里

二、整合 Mybatis 多数据源

如果开发人员配置了多个数据源,那么 Spring Boot 中 DataSource 和 Mybatis 的自动配置类将不会再生效。

1.数据库环境搭建

创建数据库dabase1后执行:

use `database1`;
-- ----------------------------
-- Table structure for teacher
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (`id` int(11) NOT NULL COMMENT '教师编号',`name` varchar(50) DEFAULT NULL COMMENT '教师姓名',`course` varchar(50) DEFAULT NULL COMMENT '所教课程',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of teacher
-- ----------------------------
INSERT INTO `teacher` VALUES ('1', 'teacher01', 'C语言');
INSERT INTO `teacher` VALUES ('2', 'teacher02', 'Java');

创建数据库dabase2后执行:

USE `database2`;
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (`id` int(11) NOT NULL COMMENT '学号',`name` varchar(50) DEFAULT NULL COMMENT '学生姓名',`age` int(11) DEFAULT NULL COMMENT '年龄',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('1', 'student01', '20');
INSERT INTO `student` VALUES ('2', 'student02', '22');

2.实体类

在entity包下创建两个实体类:

package com.tracy.mybatisdemo.entity;import lombok.Data;@Data
public class Teacher {private Integer id;private String name;/*** 所教课程*/private String course;
}
package com.tracy.mybatisdemo.entity;import lombok.Data;@Data
public class Student {private Integer id;private String name;private Integer age;
}

3.在application.yml配置数据源

spring:datasource:
#    datasource01database1:driver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://localhost:3306/database1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8username: rootpassword:
#    datasource01database2:driver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://localhost:3306/database2?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8username: rootpassword:

4.配置类配置数据源

在config包下创建DatasourceConfig类:

package com.tracy.mybatisdemo.config;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;import javax.sql.DataSource;/*** 根据配置文件中的属性值配置两个数据源datasource01和datasource02*/
@Configuration
public class DatasourceConfig {/*** 实例化数据源 datasource01*/@Bean("datasource01")// 设置该数据源为默认数据源@Primary// 以spring.datasource.database1为前缀的属性值自动绑定到对应的字段中@ConfigurationProperties(prefix = "spring.datasource.database1")public DataSource getDatasource01() {return DataSourceBuilder.create().build();}/*** 实例化数据源 datasource02*/@Bean("datasource02")@ConfigurationProperties(prefix = "spring.datasource.database2")public DataSource getDatasource02() {return DataSourceBuilder.create().build();}
}

@Primary 注解指定默认数据源,它是必要的,否则会报错。

5.配置类配置 Mybatis

给每一个数据源都创建 SqlSessionFactory 和 SqlSession 。

  • 数据源1:

在config包下创建SqlSessionConfig01类:

package com.tracy.mybatisdemo.config;import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import javax.sql.DataSource;/*** 根据数据源datasource01配置sqlSessionFactory01和sqlSession01*/
@Configuration
@MapperScan(basePackages = "com.tracy.mybatisdemo.dao.database1", sqlSessionFactoryRef = "sqlSessionFactory01")
public class SqlSessionConfig01 {/*** 向容器中实例化sqlSessionFactory01实例*/@Bean("sqlSessionFactory01")// 设置为默认SqlSessionFactory@Primarypublic SqlSessionFactory getSqlSessionFactory(// 根据名称从容器中获取实例@Qualifier("datasource01") DataSource dataSource) {try {// 实例化一个工具类,用来创建SqlSessionFactorySqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource);factoryBean.setMapperLocations(// 设置Mybatis的xml文件位置new PathMatchingResourcePatternResolver().getResources("classpath:mapper/database1/*.xml"));// 返回创建好的sqlSessionFactory实例return factoryBean.getObject();} catch (Exception e) {e.printStackTrace();}// 当创建失败时返回nullreturn null;}/*** 向容器中实例化sqlSession01实例*/@Bean("sqlSession01")// 设置为默认SqlSession@Primarypublic SqlSessionTemplate getSqlSession(@Qualifier("sqlSessionFactory01") SqlSessionFactory sqlSessionFactory) {// 利用SqlSessionFactory实例构建一个由SpringBoot管理的线程安全的SqlSessionreturn new SqlSessionTemplate(sqlSessionFactory);}
}

在config包下创建SqlSessionConfig02类:

package com.tracy.mybatisdemo.config;import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import javax.sql.DataSource;/*** 根据数据源datasource02配置sqlSessionFactory02和sqlSession02*/
@Configuration
@MapperScan(basePackages = "com.tracy.mybatisdemo.dao.database2", sqlSessionFactoryRef = "sqlSessionFactory02")
public class SqlSessionConfig02 {/*** 向容器中实例化sqlSessionFactory02实例*/@Bean("sqlSessionFactory02")// 设置为默认SqlSessionFactory@Primarypublic SqlSessionFactory getSqlSessionFactory(// 根据名称从容器中获取实例@Qualifier("datasource02") DataSource dataSource) {try {// 实例化一个工具类,用来创建SqlSessionFactorySqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource);factoryBean.setMapperLocations(// 设置Mybatis的xml文件位置new PathMatchingResourcePatternResolver().getResources("classpath:mapper/database2/*.xml"));// 返回创建好的sqlSessionFactory实例return factoryBean.getObject();} catch (Exception e) {e.printStackTrace();}// 当创建失败时返回nullreturn null;}/*** 向容器中实例化sqlSession02实例*/@Bean("sqlSession02")// 设置为默认SqlSession@Primarypublic SqlSessionTemplate getSqlSession(@Qualifier("sqlSessionFactory02") SqlSessionFactory sqlSessionFactory) {// 利用SqlSessionFactory实例构建一个由SpringBoot管理的线程安全的SqlSessionreturn new SqlSessionTemplate(sqlSessionFactory);}
}

6.编写 Dao接口和 SQL 映射文件

  • 数据库database1:

在dao包下创建文件夹database1,然后在database1下创建TeacherDao接口:

package com.tracy.mybatisdemo.dao.database1;import com.tracy.mybatisdemo.entity.Teacher;
import org.springframework.stereotype.Repository;import java.util.List;@Repository
public interface TeacherDao {List<Teacher> findAll();
}

在 resources/mapper 下新建 database1 文件夹 , 在该文件夹下新建 Mapper 接口同名的映射文件即 TeacherMapper.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.tracy.mybatisdemo.dao.database1.TeacherDao"><!--查询所有教师信息--><select id="findAll" resultType="com.tracy.mybatisdemo.entity.Teacher">select * from teacher</select>
</mapper>
  • 数据库database2:

在dao包下创建文件夹database2,然后在database2下创建StudentDao接口:

package com.tracy.mybatisdemo.dao.database2;import com.tracy.mybatisdemo.entity.Student;
import org.springframework.stereotype.Repository;import java.util.List;@Repository
public interface StudentDao {List<Student> findAll();}

在 resources/mapper 下新建 database2 文件夹 , 在该文件夹下新建 Mapper 接口同名的映射文件即 StudentMapper.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.tracy.mybatisdemo.dao.database2.StudentDao"><!--查询所有学生信息--><select id="findAll" resultType="com.tracy.mybatisdemo.entity.Student">select * from student</select>
</mapper>

7.编写controller

在controller包下创建TestController类:

package com.tracy.mybatisdemo.controller;import com.tracy.mybatisdemo.dao.database1.TeacherDao;
import com.tracy.mybatisdemo.dao.database2.StudentDao;
import com.tracy.mybatisdemo.entity.Student;
import com.tracy.mybatisdemo.entity.Teacher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
public class TestController {// 从容器中获取teacherMapper(dataSource01操作)@Autowiredprivate TeacherDao teacherDao;// 从容器中获取studentMapper(dataSource02操作)@Autowiredprivate StudentDao studentDao;/*** 从database1数据库中查询所有教师信息*/@GetMapping("/teacher")public List<Teacher> findAllTeacher() {List<Teacher> teachers = teacherDao.findAll();return teachers;}/*** 从database2数据库中查询所有学生信息*/@GetMapping("/student")public List<Student> findAllStudent() {List<Student> students = studentDao.findAll();return students;}}

8.测试

启动项目,然后在浏览器中访问http://localhost:8080/teacher和http://localhost:8080/student。

三、整合分页插件 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.Driverurl: jdbc:mysql://localhost:3306/page?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8username: rootpassword: 你的密码# Mybatis配置
# 开启驼峰式命名规则自动转换
mybatis:configuration:map-underscore-to-camel-case: true

2.添加依赖

在pom.xml中添加以下依赖:

<!--PageHelper分页插件-->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.4.3</version>
</dependency>

3.在代码中使用PageHelper

(1)entity

在entity包下创建User类:

package com.tracy.mybatisdemo.entity;import lombok.Data;// 添加Getter,Setter,toString等方法
@Data
public class User {private Integer userId;private String userName;private Integer userAge;
}

(2)dao

在dao包下创建UserDao接口:

这里为了简化使用注解绑定sql。

package com.tracy.mybatisdemo.dao;import com.tracy.mybatisdemo.entity.User;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;import java.util.List;@Repository
public interface UserDao {@Select("select user_id,user_name,user_age from tb_user")List<User> findAll();
}

(3)controller

在controller包下创建UserController类:

package com.tracy.mybatisdemo.controller;import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
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.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserDao userDao;@GetMapping("/findAll")public PageInfo<User> findAll(){//startPage静态方法,传递两个参数(当前页码,每页查询条数)PageHelper.startPage(1,3);//紧跟着的第一个select 方法会被分页List<User> list=userDao.findAll();PageInfo pageInfo = new PageInfo(list);return pageInfo;}
}

(4)测试

启动项目,然后在浏览器访问http://localhost:8080/user/findAll

页面上出现:

[{"userId":1,"userName":"user01","userAge":18},{"userId":2,"userName":"user02","userAge":19},{"userId":3,"userName":"user03","userAge":18}]

成功!

(5)返回类PageInfo

此类是插件里封装好的类,可以了解一下:

public class PageInfo<T> implements Serializable {private static final long serialVersionUID = 1L;
//当前页
private int pageNum;
//每页的数量
private int pageSize;
//当前页的数量
private int size;
//由于startRow 和endRow 不常用,这里说个具体的用法
//可以在页面中"显示startRow 到endRow 共size 条数据"
//当前页面第一个元素在数据库中的行号
private int startRow;
//当前页面最后一个元素在数据库中的行号
private int endRow;
//总记录数
private long total;
//总页数
private int pages;
//结果集
private List<T> list;
//前一页
private int prePage;
//下一页
private int nextPage;
//是否为第一页
private boolean isFirstPage = false;
//是否为最后一页
private boolean isLastPage = false;
//是否有前一页
private boolean hasPreviousPage = false;
//是否有下一页
private boolean hasNextPage = false;
//导航页码数
private int navigatePages;
//所有导航页号
private int[] navigatepageNums;
//导航条上的第一页
private int navigateFirstPage;
//导航条上的最后一页
private int navigateLastPage;
}

四、整合 Mybatis-Plus

Mybatis-Plus (简称 MP )是由国内 baomidou 组织开源的 Mybatis 的增强工具。在原生 Mybatis 的基础上只做增强不做改变,为简化开发,提高效率而生。

在使用过程中,MP 提供了一套通用的 Mapper 和 Service 操作,只需要继承接口,进行简单的配置便可以进行单表的 CRUD 操作。对于一些复杂的查询,提供了使用数据库字段和 POJO 属性两种方式来构造条件进行查询。此外,它自带乐观锁、性能分析插件、代码生成器和物理分页插件等特色功能。

1.数据库搭建、配置

数据库搭建和上一章一模一样。

配置application.yml:

# 数据源
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/page?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8username: rootpassword: # MyBatis-Plus的设置
# 别名包扫描路径,为路径下的所有类创建别名
mybatis-plus:type-aliases-package: com.tracy.mybatisdemo.entity# xml扫描路径。然后在Mapper接口写上自定义方法并关联XML语句,即可实现手写SQLmapper-locations: classpath*:mapper/*.xml# MyBatis-Plus驼峰转换,配置后不论手写SQL还是接口方法,都能自动映射(默认on)configuration:map-underscore-to-camel-case: on# 配置生成SQL日志log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2.添加依赖

<!--Mybatis-Plus启动器-->
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.1</version>
</dependency>

3.代码实现

com.tracy.mybatisdemo目录下需要5个包:entity、dao、service、controller、config。resources目录下需要有mapper文件夹。

(1)entity

创建一个 User 实体类:

package com.tracy.mybatisdemo.entity;import lombok.Data;
import com.baomidou.mybatisplus.annotation.*;// 建立实体类和数据库表之间的对应关系
@TableName("tb_user")
// 添加getter,setter,toString等方法
@Data
public class User {// 用于标识数据库表的主键字段,MP 默认数据库表中名为 id 的字段是主键,如若不是,需通过该注解进行标识。// type = IdType.AUTO 表示数据库主键自增@TableId(value = "user_id", type = IdType.AUTO)private Integer id;// 建立实体类字段和数据库表属性之间的对应关系,当两者相同时可省略该注解。@TableFieldprivate String userName;private Integer userAge;}

在 MP 中,自动支持实体类字段按照驼峰转下划线形式的进行转换。

(2)dao

创建UserDao接口:

package com.tracy.mybatisdemo.dao;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tracy.mybatisdemo.entity.User;
import org.springframework.stereotype.Repository;@Repository
// 继承Mybatis-Plus提供的BaseMapper,提供基础的CRUD及分页方法
public interface UserDao extends BaseMapper<User> {}

BaseMapper:

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;@Service
public 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 {/*** 添加分页插件*/@Beanpublic 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 {@Autowiredpublic 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中测试每个方法,不再赘述。

Spring boot 实战指南(二):Mybatis、动态绑定、多数据源、分页插件、Mybatis-Plus相关推荐

  1. Spring Boot 实战 —— MyBatis(注解版)使用方法

    原文链接: Spring Boot 实战 -- MyBatis(注解版)使用方法 简介 MyBatis 官网 是这么介绍它自己的: MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过 ...

  2. 最新Spring Boot实战项目(权限后台管理系统)详解

    Spring Boot实战项目 - 权限后台管理系统 简介 这是一套基于spring boot 2.16.shiro.jwt.redis.swagger2.mybatis .thymeleaf.lay ...

  3. Spring Boot实战系列《六》:人事管理系统的登录设计

    Spring Boot实战系列<六>:人事管理系统的登录设计 Spring Boot实战系列<六>:人事管理系统的登录设计 1.前言 在上一篇中教大家在IEDA或者eclips ...

  4. Spring Boot实战解决高并发数据入库: Redis 缓存+MySQL 批量入库

    前言 最近在做阅读类的业务,需要记录用户的PV,UV: 项目状况:前期尝试业务阶段: 特点: 快速实现(不需要做太重,满足初期推广运营即可) 快速投入市场去运营 收集用户的原始数据,三要素: 谁 在什 ...

  5. 那些在《JavaEE开发的颠覆者 Spring Boot实战》中遇到的坑,,。(一)

    一.一开始下了一本PDF书,影印版,看一般的字还是看的清,但是看到代码部分的话,还是会有模糊,尤其是一些配置的时候,后来是在不行就去网上搜了一下,找到一个网易云阅读上有网页版的<JavaEE开发 ...

  6. spring boot 实战 / 可执行war启动参数详解

    概述   上一篇文章<spring boot 实战 / mvn spring-boot:run 参数详解>主要讲解了spring boot 项目基于maven插件启动过程中借助profil ...

  7. Spring Boot实战:过滤器、拦截器与切片

    Spring Boot实战:过滤器.拦截器与切片 Q:使用过滤器.拦截器与切片实现每个请求耗时的统计,并比较三者的区别与联系 过滤器Filter 过滤器概念 Filter是J2E中来的,可以看做是Se ...

  8. Spring Boot实战pdf

    下载地址:网盘下载 Spring Boot实战以Spring应用程序开发为中心,全面讲解如何运用Spring Boot提高效率,使应用程序的开发和管理更加轻松有趣.作者行文亲切流畅,以大量示例讲解了S ...

  9. spring boot实战(第六篇)加载application资源文件源码分析

    前言 在上一篇中了解了spring配置资源的加载过程,本篇在此基础上学习spring boot如何默认加载application.xml等文件信息的. ConfigFileApplicationLis ...

最新文章

  1. Kinect For Windows V2开发日志一:开发环境的配置
  2. python练习题:给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度
  3. 诗和远方:无题(四十七)
  4. android xml 多行注释,C#中的XML多行注释 - 我做错了什么?
  5. clion变量配置_cygwin安装和clion配置
  6. 201671010439-词频统计软件项目报告
  7. Precious Plastic 中文手册 V1.0
  8. 手把手搭个vue的脚手架 - 2. 模板搭建
  9. 存储和多屏互动,蜂鸟网的NAS应用解析
  10. 中科院计算机研究所排名,中国科学院计算技术研究所
  11. python 预测任意天后股票数据_python股票预测算法
  12. wishbone协议(B.3)下载地址
  13. 纯css3实现图片自动切换
  14. 3dmax文件打不开了,怎么办
  15. Android 开发、测试工具资源汇总
  16. Mybatis--SqlSession对象创建过程
  17. Tex插入各种希腊字母
  18. 以太坊NFT二层网络之Immutable X(IMX)
  19. Graph Mixture Density Networks 图混合密度网络
  20. t - 分布的区间估计

热门文章

  1. VS中实时获取SVN的版本号并写入到AssemblyInfo.cs中(C#)
  2. 如何关闭iPhone浏览器自动将数字识别为电话号码
  3. oracle:使用cmd命令在远程oracle服务器上执行sql语句
  4. Python 京东爬虫抢手机小程序
  5. 五金机电行业智能供应链管理系统解决方案:数智化供应链为传统产业“造新血”
  6. [P3371 ]【模板】单源最短路径
  7. JDBC问题: Unknown error 1146 Query
  8. java字符串==_Java字符串(String)
  9. 通知栏通知不被清除通知所取消
  10. 六十星系之01紫微独坐子午