SpringBoot整合Mybatis-Plus

SpringBoot整合Mybatis-Plus

文章目录

  • SpringBoot整合Mybatis-Plus
    • 前言
    • 新建项目
    • 配置连接
    • 快速入门
    • 常用注解
      • @TableName
      • @TableId
      • @TableField
    • 常用方法
      • 查询方法
      • 增加方法
      • 更新方法
      • 删除方法
    • 分页查询
    • 多数据源配置
    • 参考文章

前言

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

正如官方文档中所提到的,Mybatis-Plus拥有很多优秀的特性:

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

Mybatis-Plus 作为更优秀的持久层框架,继续沿用了 ORM 的思想,也支持很多的数据库连接

  • mysql 、 mariadb 、 oracle 、 db2 、 h2 、 hsql 、 sqlite 、 postgresql 、 sqlserver 、 presto
  • 达梦数据库 、 虚谷数据库 、 人大金仓数据库

SpringBoot整合Mybatis-Plus_第1张图片

官方也给出了免费的第三方视频可供学习:

  • MyBatis-Plus 入门 - 视频教程 - 慕课网

  • MyBatis-Plus 进阶 - 视频教程 - 慕课网

Mybatis-Plus 的知识并不少,不是三言两语能够讲清楚的。这里选取了 Mybatis-Plus 的部分基础要点与 SpringBoot 进行整合学习,以练促学,达到以点带面的效果。

如果想要更近一步的学习 Mybatis-Plus 的高级应用,还是拿官网文档学习为最佳。

新建项目

使用 IDEA 工具新建 SpringBoot 项目,初始化组件选择 lombokSpring WebMySQL Driver

pom.xml 文件中引入 Mybatis-Plus 依赖、阿里巴巴的 druid 连接池

<dependency>
    <groupId>com.baomidougroupId>
    <artifactId>mybatis-plus-boot-starterartifactId>
    <version>3.2.0version>
dependency>
<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>druidartifactId>
    <version>1.1.19version>
dependency>

配置连接

新建 dao 目录,在主程序中配置 Mapper 扫描

@SpringBootApplication
@MapperScan("com.example.dao")
public class SpringbootMybatisplusApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootMybatisplusApplication.class, args);
    }
}

使用 Navicat 在 MySQL 中新建一个名为 mybatisplus 的数据库

SpringBoot整合Mybatis-Plus_第2张图片

新建 application.yml 文件,进行基本配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatisplus? useUnicode=true & useSSL=false &
      characterEncoding=utf-8 & serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    type: com.alibaba.druid.pool.DruidDataSource

# 配置日志
logging:
  level: 
    root: info
    com:
      example:
        dao: debug

这里因为 Mybatis-plus 内置了很多 sql 的增删改查方法,足够我们应付大多数的应用场景,(相当于提供了零 xml 配置的特性),所以我们不需要再通过 mapper-locations 进行 xml 文件的指定,如果有特殊需要再去做。同时,我们也不用通过 type-aliases-package: 对实体类器别名,mybatis-plus 会自动为实体类起别名。

我们去 mybatisplus 数据库中新建一个 user

DROP TABLE IF EXISTS user;

CREATE TABLE user(
	id VARCHAR(11) NOT NULL AUTO_INCREMENT,
	name VARCHAR(25) DEFAULT NULL,
	age INT(11) DEFAULT NULL,
	bir TIMESTAMP NULL DEFAULT NULL,
	PRIMARY KEY(id)
)ENGINE=INNODB DEFAULT charset=utf8;

随便插入几条数据

SpringBoot整合Mybatis-Plus_第3张图片

快速入门

新建 entity 目录,目录下新建 User 类

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class User {
    private String id;
    private String name;
    private Integer age;
    private Date bir;
}

@Accessors 是 lombok 的一个注解,翻译为存取器,通过该注解可以控制getter和setter方法的形式。chain 为 true,则setter方法返回当前对象。

//没加Accessors(chain = true) 
public void setName(String name) {
    this.name = name;
}
//加了Accessors(chain = true) 
public User setName(String name) {
    this.name = name;
    return this;
}

在 dao 目录下新建 UserDao 接口。

我们要想在 Dao 层接口中使用 mybatis-plus 的增强,只需要继承 BaseMapper<实体类>,就可以调用 mybatis-plus 封装好的增删改查方法。

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.entity.User;
import org.springframework.stereotype.Repository;

//使用mybatisplus增强结果
public interface UserDao extends BaseMapper<User> {
}

我们通过测试类进行测试

如果 userDao 标红,提示说不能自动装配也没有关系,测试类也是可以运行起来的

SpringBoot整合Mybatis-Plus_第4张图片

@SpringBootTest
class SpringbootMybatisplusApplicationTests {
    @Autowired
    private UserDao userDao;

    //查询所有
    @Test
    public void testFindAll(){
        List<User> users = userDao.selectList(null);//参数为空默认查询所有数据
        // lambda表达式
        users.forEach(user -> System.out.println("user = "+ user));
    }
}

可以看到,我们已经轻松查询到了 user 表中的数据

SpringBoot整合Mybatis-Plus_第5张图片

常用注解

我们在使用 mybatis-plus 的时候,最常用的是三个注解

  • @TableName
  • @TableId
  • @TableField

@TableName

  • 描述:表名注解,用来将实体对象与数据库表名完成映射
  • 修饰范围:用在实体类上
  • 常见属性:
    • value:String类型,指定映射的表名(如果为空则默认将类名用来映射表名)
    • resultMap:String类型,用来指定 xml 配置中 resultMap 的 id 值(仅限于自己使用复杂resultMap时使用)

@TableId

  • 描述:主键注释,用来将实体类中的属性与数据表中的主键完成映射
  • 修饰范围:用在实体类的属性上
  • 常见属性:
    • value:String类型,指定实体类中与表中对应的主键列名
    • type:枚举类型,指定主键生成类型

IdType

描述
AUTO 数据库ID自增
NONE 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUT insert前自行set主键值
ASSIGN_ID 分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),
使用接口IdentifierGenerator的方法nextId
(默认实现类为DefaultIdentifierGenerator雪花算法)
ASSIGN_UUID 分配UUID,主键类型为String(since 3.3.0),
使用接口IdentifierGenerator的方法nextUUID(默认default方法)

@TableField

  • 描述:字段注解(非主键),用来将实体类中的属性与数据表中的字段完成映射
  • 修饰范围:用在实体类的属性上
  • 常见属性:
    • value:String类型,指定实体类中与表中对应的字段名(如果为空则默认将属性名用来映射字段名)
    • exist:boolean类型,判断是否为数据库表字段,false表示不是数据表的字段

对于我们刚才建立的实体类来说,我们也可以这样编写

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@TableName("user")//数据表名
public class User {
    @TableId(value = "id", type = IdType.AUTO)//自增主键
    private String id;
    @TableField(value = "name")
    private String name;
    private int age;
    private Date bir;

    @TableField(exist = false)//不映射数据表中的任何字段
    private String email;
}

重新运行测试类:

m6

常用方法

查询方法

  • 查询所有
//查询所有
@Test
public void testFindAll(){
    List<User> users = userDao.selectList(null);//参数为空默认查询所有数据
    users.forEach(user -> System.out.println("user = "+ user));
}
  • 根据主键查询
//根据主键查询一个
@Test
public void testFindById(){
    User user = userDao.selectById(1);
    System.out.println("user = "+user);
}
  • 条件查询
//条件查询
@Test
public void testFind(){
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("age", 23);//设置等值查询
    //queryWrapper.lt("age", 23);//设置小于查询
    //queryWrapper.le("age", 23);//设置小于等于查询
    //ne对应不等于,gt对应大于,ge对应大于等于······

    List<User> users = userDao.selectList(queryWrapper);
    users.forEach(user -> System.out.println("user = "+user));
}
  • 模糊查询
//模糊查询
@Test
public void testFindLike(){
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    // like %?%
    queryWrapper.like("name", "o");

    //likeLeft %? 以xxx结尾的
    //likeRight ?% 以xxx开头的

    List<User> users = userDao.selectList(queryWrapper);
    users.forEach(user -> System.out.println("user = "+ user));
}

模糊查询的结果为:

m7

增加方法

//增加一条记录
@Test
public void testInsert(){
    User user = new User();
    user.setName("Jerry").setAge(23).setBir(new Date());
    userDao.insert(user);
}

可以看到,数据表中已经成功添加了一条记录

SpringBoot整合Mybatis-Plus_第6张图片

更新方法

//基于主键id进行数据修改
@Test
public void testUpdateById(){
    //修改3号的名字为Kafka
    User user = userDao.selectById(3);
    user.setName("Kafka");
    userDao.updateById(user);
}
//批量修改
@Test
public void testUpdate(){
    //将age为23的所有人名字修改为Chris
    User user = new User();
    user.setName("Chris");
    
    QueryWrapper<User> updateWrapper = new QueryWrapper<>();
    updateWrapper.eq("age", 23);
    userDao.update(user, updateWrapper);
}

可以看到,第一个更新方法将 3 号的名字更新为 Kafka,第二个更新方法将年龄为23的两个人名字改成了 Chris

SpringBoot整合Mybatis-Plus_第7张图片

删除方法

//基于Id删除一条记录
@Test
public void testDeleteById() {
    userDao.deleteById(3);
}
//基于条件进行删除
@Test
public void testDelete(){
    //删除年龄>=23的所有人
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.ge("age", "23");
    userDao.delete(queryWrapper);
}

可以看到,第一个方法删除了3号记录,第二个方法删除了年龄>=23的所有人

SpringBoot整合Mybatis-Plus_第8张图片

分页查询

注意,当前 Mybatis-Plus 的分页插件只支持单表查询,不支持多表连接查询

我们刚才测试删除方法时已经将数据删除得所剩无几了,先往里插入几条数据

SpringBoot整合Mybatis-Plus_第9张图片

新建 config 目录,在目录下新建 UserPage

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement
@Configuration
@MapperScan("com.example.dao")
public class UserPage {
    //分页的拦截器依赖
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        return paginationInterceptor;
    }
}

继续在测试类中进行测试:

  • 不带条件的分页查询
//不带条件分页查询
@Test
public void testPage(){
    //参数1:当前页,默认是1
    // 参数2:每页显示记录数,默认为10
    IPage<User> page = new Page<>(1, 2);
    IPage<User> userIPage = userDao.selectPage(page, null);

    //查看总数,并遍历
    long total = userIPage.getTotal();
    System.out.println("总记录数:" + total);
    userIPage.getRecords().forEach(user -> System.out.println("user = " + user));
}

m12

  • 带条件的分页查询
//带条件分页查询
@Test
public void testPage2(){
    IPage<User> page = new Page<>(1, 2);
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //根据返回年龄为20的记录做分页
    queryWrapper.eq("age", 23);

    IPage<User> userIPage = userDao.selectPage(page, queryWrapper);
    //查看总数,并遍历
    long total = userIPage.getTotal();
    System.out.println("总记录数:" + total);
    userIPage.getRecords().forEach(user -> System.out.println("user = " + user));
}

m13

多数据源配置

为了确保数据库产品的稳定性,很多数据库拥有双机热备份功能。

  • 第一台数据库服务器,是对外提供增删改业务的生产服务器
  • 第二台数据库服务器,主要进行读的操作

这里我们就不用服务器进行演示了,直接用本机上两个不同的数据库来模拟不同的 MySQL 服务

dynamic-datasource-spring-boot-starter 是一个基于 springboot 的快速集成多数据源的启动器,我们需要在 pom.xml 文件中引入依赖

<dependency>
  <groupId>com.baomidougroupId>
  <artifactId>dynamic-datasource-spring-boot-starterartifactId>
  <version>3.0.0version>
dependency>

application.properties 文件中配置数据源(清空 application.yml)

spring.datasource.primary=master    # 指定默认数据源
spring.datasource.dynamic.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.dynamic.datasource.master.url=jdbc:mysql://localhost:3306/mybatisplus? \
    useUnicode=true & characterEncoding=utf-8 & serverTimezone=Asia/Shanghai
spring.datasource.dynamic.datasource.master.username=root
spring.datasource.dynamic.datasource.master.password=123456

# 一主一丛,主数据源名称为 master,从数据源名称为 slave_1
# 一主多从同理
spring.datasource.dynamic.datasource.slave_1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.dynamic.datasource.slave_1.url=jdbc:mysql://localhost:3306/mybatisplus2? \
    useUnicode=true & characterEncoding=utf-8 & serverTimezone=Asia/Shanghai
spring.datasource.dynamic.datasource.slave_1.username=root
spring.datasource.dynamic.datasource.slave_1.password=123456

Navicat 中新建一个数据库 mybatisplus2作为从库,将主库中的 user 表复制过来,保证主库和从库的数据一致。

SpringBoot整合Mybatis-Plus_第10张图片

当我们要进行数据的业务切换时,需要在业务层进行,在 Dao 层是不行的

新建 service 目录,目录下新建 UserService 接口

public interface UserService {
    //查询方法
    List<User> findAll();
    //添加方法
    void insert(User user);
}

在同级目录下,新建 UserServiceImpl 类,借助 Dao 层实现这个接口

import com.example.dao.UserDao;
import com.example.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional
public class UserServiceImpl implements UserService{
    @Autowired
    private UserDao userDao;

    @Override
    public List<User> findAll() {
        return userDao.selectList(null);
    }

    @Override
    public void insert(User user) {
        userDao.insert(user);
    }
}

在 test 包下,新建一个测试类 TestUserService

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
public class TestUserService {

    @Autowired
    private UserService userService;

    @Test
    public void testFindAll(){
        userService.findAll().forEach(user -> System.out.println("user = "+ user));
    }
}

运行 testFindAll() 方法,会默认从主库中取出数据

SpringBoot整合Mybatis-Plus_第11张图片

dynamic这个启动器为我们引入了 @DS 这个注解

@DS:

  • 作用:用于切换数据源的注解
  • 修饰范围:方法上或类上。
    • 如果用在类上注解,则表明类中所有方法都使用这个数据源
    • 如果用在方法上注解,则优先于类上的注解(局部优先原则)
  • value属性:切换数据源的名称

现在主库和从库的数据是一致的,即使切换了也看不出来效果,因此我们先去修改一下从库的数据。我们把1号的名字由英文改为中文

SpringBoot整合Mybatis-Plus_第12张图片

然后我们去 UserServiceImpl 类中切换数据源。因为 @DS 注解遵循局部优先原则,那么findAll()一定会到从数据源取数据

@Service
@Transactional
@DS("master")
public class UserServiceImpl implements UserService{
    @Autowired
    private UserDao userDao;

    @Override
    @DS("slave_1")
    public List<User> findAll() {
        return userDao.selectList(null);
    }

    @Override
    public void insert(User user) {
        userDao.insert(user);
    }
}

再次运行测试类可以发现,findAll() 方法会到从库中去取数据

SpringBoot整合Mybatis-Plus_第13张图片

我们接着在测试类编写插入的方法

@Test
public void testInsert(){
    User user = new User();
    user.setName("Nomun").setAge(22).setBir(new Date());
    userService.insert(user);
}

运行该方法可以看到,主库中已经增加了这条记录

SpringBoot整合Mybatis-Plus_第14张图片

因为我们并没有配置主从同步,所以从库中没有插入这条记录

SpringBoot整合Mybatis-Plus_第15张图片

参考文章

MyBatis-Plus 官方文档

Mybatis-Plus整合SpringBoot实战教程,提高的你开发效率,后端人员必备!

lombok @Accessors用法

你可能感兴趣的:(SpringBoot)