MyBatisPlus

MyBatisPlus

介绍

MyBatisPlus 是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。MyBatisPlus 提供了通用的 mapper 和 service,可以在不编写任何 SQL 语句的情况下,快速实现对单表的 CRUD、批量、逻辑删除、分页等操作。

特性

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

基于 SpringBoot3 的 MyBatis-Plus 依赖

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

		<dependency>
			<groupId>com.mysql</groupId>
			<artifactId>mysql-connector-j</artifactId>
			<scope>runtime</scope>
		</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>


		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.5.3.1</version>
		</dependency>


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

BaseMapper 的增删改查

实体类

package cn.test.mybatisplus.bean;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("t_user")
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

Mapper

@Repository
public interface UserMapper extends BaseMapper<User> {
}

注意:在 SpringBoot 主程序中需要使用 @MapperScan 注解声明 mapper 的扫描路径

@SpringBootApplication
@MapperScan("cn.test.mybatisplus.mapper")
public class MybatisPlusApplication {

	public static void main(String[] args) {
		SpringApplication.run(MybatisPlusApplication.class, args);
	}

}

测试类

package cn.test.mybatisplus;

import cn.test.mybatisplus.bean.User;
import cn.test.mybatisplus.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.*;

@SpringBootTest
class MybatisPlusApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testUserInsert() {
        User user = new User();
        user.setAge(18);
        user.setName("张山");
        user.setEmail("12345@qq.com");
        userMapper.insert(user);
    }

    @Test
    public void testUserQuery() {
        List<User> users = userMapper.selectList(null);
        System.out.println(users);
    }

    @Test
    public void testQuery2(){
        User user = userMapper.selectById(1L);
        System.out.println(user);
    }

    @Test
    public void testQuery3(){
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1L,2L));
        System.out.println(users);
    }

    @Test
    public void testQuery4(){
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("name","tom");
        map.put("age",18);
        List<User> users = userMapper.selectByMap(map);
        System.out.println(users);
    }

    @Test
    public void testDelete1() {
        int result = userMapper.deleteById(1722526489091670018L);
        System.out.println("result: " + result);
    }

	@Test
	public void testDelete2() {
		Map<String,Object> map = new HashMap<String,Object>();
		map.put("name","tom");
		map.put("age",18);
		int result = userMapper.deleteByMap(map);
		System.out.println("result: " + result);
	}

	@Test
	public void testDelete3(){
		List<Long> ids = new ArrayList<>();
		ids.add(1L);
		ids.add(2L);
		int result = userMapper.deleteBatchIds(ids);
		System.out.println("result: " + result);
	}

    @Test
    public void testUpdate(){
        User user = new User();
        user.setId(1L);
        user.setName("jerry");
        userMapper.updateById(user);
    }
}

自定义方法进行操作

在 Mapper 中添加方法进行操作

@Repository
public interface UserMapper extends BaseMapper<User> {
	List<User> getUserById(@Param("id") Long id);
}

Mapper.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="cn.test.mybatisplus.mapper.UserMapper">
    <select id="getUserById" resultType="User">
        select id,name,age,email from t_user where id = #{id}
    </select>
</mapper>

在配置文件中开启别名的包名

mybatis-plus:
  type-aliases-package: cn.test.mybatisplus.bean

Service CRUD 接口

  • 通用 Service CRUD 封装 IService 接口,进一步封装 CRUD,采用 get 查询单行,remove 删除,list 查询集合,page 分页 这些前缀命名区分 Mapper 层避免混淆
  • 泛型 T 为任意实体对象
  • 如果存在自定义通用 Service 方法的可能,请创建自己的 IBaseService 继承 Mybatis-Plus 提供的基类
  • 对象 Wrapper 为条件构造器

UserService

package cn.test.mybatisplus.service;

import cn.test.mybatisplus.bean.User;
import com.baomidou.mybatisplus.extension.service.IService;

public interface UserService extends IService<User> {
}

UserService 实现类

package cn.test.mybatisplus.service.impl;

import cn.test.mybatisplus.bean.User;
import cn.test.mybatisplus.mapper.UserMapper;
import cn.test.mybatisplus.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

测试类

package cn.test.mybatisplus;

import cn.test.mybatisplus.bean.User;
import cn.test.mybatisplus.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;
import java.util.List;

@SpringBootTest
public class UserServiceTest {


    @Autowired
    private UserService userService;

    @Test
    public void testSaveBatch(){
        List<User> list = new ArrayList<>();
        for (int i = 1; i < 6; i++) {
            User user = new User();
            user.setName("zhangshan"+i);
            user.setAge(18+i);
            list.add(user);
        }
        boolean b = userService.saveBatch(list);
        System.out.println(b);
    }
    
    @Test
    public void testList(){
        List<User> list = userService.list();
    }
    
    @Test
    public void testGet(){
        User user = userService.getById(1L);
    }
    
    @Test
    public void testUpdate(){
        User user = new User();
        user.setId(1L);
        user.setAge(30);
        userService.updateById(user);
    }

    @Test
    public void testDelete(){
        User user = new User();
        user.setId(1L);
        userService.removeById(user);
    }
    
}

Mybatis-Plus 注解

@TableName()

指定表名 @TableName(“表名”)

@TableId

  1. 指定该属性为主键

  2. 如果数据库主键字段和实体类的主键属性不一致时,可以使用 @TableId(“主键字段名”) 来指定主键字段名

  3. 如果不使用 myBatis-Plus 主键的雪花算法,而是采用自增主键。可以使用 @TableId(type = IdType.AUTO) type 属性来指定

@TableField

指定属性对应的数据库的的字段名 @TableField(“字段名”)

@TableLogic

逻辑删除指定一个 Integer 字段 0 表示未删除,1 表示逻辑删除,并且该字段使用 @TableLogic 修饰

全局配置表名的前缀

mybatis-plus:
  global-config:
    db-config:
      table-prefix: t_

全景配置统一的主键生成策略

mybatis-plus:
  global-config:
    db-config:
      id-type: auto

雪花算法

雪花算法是 Twitter 公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键具有时序性
核心思想

  • 长度共 64 位
    首先是一个符号位,1 bit 标识,由于 long 基本类型在 java 中是带符号的,最高位是符号位,正数是 0,负数是 1,所以 id 一般是正数,最高位为 0
    41 bit 时间戳(毫秒级)存储的是时间戳的差值(当前时间 - 开始时间戳),结果约等于 69.73 年。
    10 bit 最为机器的 ID (5 个 bit 是数据中心,5 个 bit 是机器 ID,可以部署在 1024 个节点)
    12 bit 作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID)
  • 优点
    整体上按照时间进行自增排序,并且整个分布式系统内不会产生 ID 碰撞,并且效率高。

条件构造器

  • Wrapper:条件构造器抽象类,最顶层基类
    • AbstractWrapper:用于查询条件封装,生成 sql 的 where 条件
      • QueryWrapper:查询条件封装
      • UpdateWrapper:Update 条件封装
      • AbstractLambdaWrapper:使用 Lambda 语法
        • LambdaQueryWrapper:用于 Lambda 语法使用的查询 Wrapper
        • LambdaUpdateWrapper:Lambda 更新封装 Wrapper
package cn.test.mybatisplus;


import cn.test.mybatisplus.bean.User;
import cn.test.mybatisplus.mapper.UserMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.junit.jupiter.api.Test;
import org.junit.platform.commons.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;
import java.util.Map;

@SpringBootTest
public class WrapperTest {

    @Autowired
    private UserMapper mapper;


    @Test
    public void test() {
        //QueryWrapper 查询
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
        queryWrapper.like("name", "a").between("age", 20, 22).isNotNull("email");
        List<User> users = mapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }

    @Test
    public void test1() {
        //QueryWrapper 查询并排序
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
        queryWrapper.orderByDesc("age");
        List<User> users = mapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }

    @Test
    public void test2() {
        //QueryWrapper删除
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
        queryWrapper.isNull("email");
        int delete = mapper.delete(queryWrapper);
        System.out.println(delete);
    }


    @Test
    public void test3() {
        //使用QueryWrapper更新
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
        queryWrapper.gt("age", 20)
                .like("name", "a")
                .or()
                .isNull("email");
        User user = new User();
        user.setName("tom");
        user.setEmail("tom@qq.com");
        int update = mapper.update(user, queryWrapper);
        System.out.println(update);
    }


    @Test
    public void test4() {
        // lambda 表达式
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
        queryWrapper.like("name", "a")
                .and(c -> c.gt("age", 20).or().isNull("email"));
        User user = new User();
        user.setName("tom");
        user.setEmail("tom@qq.com");
        int update = mapper.update(user, queryWrapper);
        System.out.println(update);
    }

    @Test
    public void test5() {
        //查询部分字段
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
        queryWrapper.select("name", "age");
        List<Map<String, Object>> maps = mapper.selectMaps(queryWrapper);
    }


    @Test
    public void test6() {
        //子查询
        QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
        queryWrapper.inSql("id", "select * from t_user where id <= 100");
        List<User> users = mapper.selectList(queryWrapper);
        users.forEach(System.out::println);
    }


    @Test
    public void test7() {
        //UpdateWrapper 更新
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<User>();
        updateWrapper.like("name", "a")
                .and(c -> c.gt("age", 20).or().isNull("email"));
        updateWrapper.set("name", "tom").set("age", 40);
        int update = mapper.update(null, updateWrapper);
        System.out.println(update);
    }


    @Test
    public void test8() {
        // 带条件的判断
        String name = "a";
        Integer ageStart = null;
        Integer ageEnd = 30;
        //UpdateWrapper 更新
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<User>();
        updateWrapper.like(StringUtils.isNotBlank(name), "name", name)
                .and(c -> c.ge(ageStart != null, "age", ageStart)
                        .le(ageEnd != null, "age", ageEnd)
                        .or().isNull("email"));
        updateWrapper.set("name", "tom").set("age", 40);
        int update = mapper.update(null, updateWrapper);
        System.out.println(update);
    }


    @Test
    public void test9() {
        String name = "a";
        Integer ageStart = null;
        Integer ageEnd = 30;
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(name), User::getName, name)
                .ge(ageStart != null, User::getAge, ageStart)
                .le(ageEnd != null, User::getAge, ageEnd)
                .or().isNull(User::getEmail);
        User user = new User();
        user.setName("tom");
        user.setEmail("tom@qq.com");
        int update = mapper.update(user, queryWrapper);
        System.out.println(update);
    }


    @Test
    public void test10() {
        String name = "a";
        Integer ageStart = null;
        Integer ageEnd = 30;
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.like(StringUtils.isNotBlank(name), User::getName, name)
                .ge(ageStart != null, User::getAge, ageStart)
                .le(ageEnd != null, User::getAge, ageEnd)
                .or().isNull(User::getEmail);
        updateWrapper.set(User::getName, name).set(User::getAge,20);
        int update = mapper.update(null, updateWrapper);
        System.out.println(update);
    }
}

MyBatis-Plus 分页插件

Mybatis-plus自带分页方法

配置分页插件

package cn.test.mybatisplus.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisPlusConfig {

    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return mybatisPlusInterceptor;
    }
}

测试代码

package cn.test.mybatisplus;

import cn.test.mybatisplus.bean.User;
import cn.test.mybatisplus.mapper.UserMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class MybatisPageTest {


    @Autowired
    private UserMapper userMapper;
    public void test(){
        Page<User> page = new Page<User>(1,3);
        userMapper.selectPage(page,null);
        System.out.println(page.getRecords());
        System.out.println(page.getTotal());
        System.out.println(page.getPages());
        System.out.println(page.hasNext());
        System.out.println(page.hasPrevious());
    }
}

自定义分页

Mapper

@Repository
public interface UserMapper extends BaseMapper<User> {
    Page<User> queryPage(@Param("page") Page<User> page,@Param("age") Integer age);
}

Mapper.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="cn.test.mybatisplus.mapper.UserMapper">
  <select id="queryPage" resultType="User">
        select id,name,age,email from t_user where age >= #{age}
  </select>
</mapper>

测试方法

  @Test
    public void test2(){
        Page<User> page = new Page<User>(1,3);
        userMapper.queryPage(page,20);
    }

乐观锁

乐观锁插件

@Configuration
public class MyBatisPlusConfig {

    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

在实体类中和表中增加一个 version 字段,使用 @Version 标志 version 字段,在修改时 version 加 1

通用枚举

SexEnum

@Getter
public enum SexEnum{

	MALE(1,"男")FEMALE(2"女");
	@EnumValue
	private Integer sex;
	private String sexName;
	SexEnum(Integer sex,String sexName){
		this.sex = sex;
		this.sexName = sexName;
	}
	
}

配置 mybatis-plus 扫描通用枚举

mybatis-plus:
  type-enums-packages: cn.test.enums

代码生成器

<!--代码生成器依赖-->
<dependency>
   <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.0.5</version>
</dependency>

<!--代码生成器用到的引擎-->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.2</version>
</dependency>

生成器代码

FastAutoGenerator.create("url", "username", "password")
    .globalConfig(builder -> {
        builder.author("baomidou") // 设置作者
            .enableSwagger() // 开启 swagger 模式
            .fileOverride() // 覆盖已生成文件
            .outputDir("D://"); // 指定输出目录
    })
    .dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
        int typeCode = metaInfo.getJdbcType().TYPE_CODE;
        if (typeCode == Types.SMALLINT) {
            // 自定义类型转换
            return DbColumnType.INTEGER;
        }
        return typeRegistry.getColumnType(metaInfo);

    }))
    .packageConfig(builder -> {
        builder.parent("com.baomidou.mybatisplus.samples.generator") // 设置父包名
            .moduleName("system") // 设置父包模块名
            .pathInfo(Collections.singletonMap(OutputFile.xml, "D://")); // 设置mapperXml生成路径
    })
    .strategyConfig(builder -> {
        builder.addInclude("t_simple") // 设置需要生成的表名
            .addTablePrefix("t_", "c_"); // 设置过滤表前缀
    })
    .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
    .execute();

多数据源

依赖

<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  <version>${version}</version>
</dependency>

配置数据源

spring:
  datasource:
    dynamic:
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      datasource:
        master:
          url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
        slave_1:
          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
        slave_2:
          url: ENC(xxxxx) # 内置加密,使用请查看详细文档
          username: ENC(xxxxx)
          password: ENC(xxxxx)
          driver-class-name: com.mysql.jdbc.Driver
       #......省略
       #以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2

使用 @DS 切换数据源。

@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。

MyBatisX 插件

  1. 在 idea 的 plugin 中下载 MyBatisX
  2. 在右侧 database 中连接数据库
  3. 右击选择需要自动生成代码的数据库表

Generate Options配置

第一页配置

  • module path:模块路径
  • base package:包名
  • encoding:保持默认 utf-8
  • superClass:基类
  • base path:src/main/java
  • ignore field prefix:忽略属性前缀
  • ignore table prefix:忽略表的前缀,如 t_
  • relative package:实体类的包名
  • ignore field suffix:忽略属性的后缀
  • ignore table suffix:忽略表名后缀

第二页配置

  • annotation:选 Mybatis-Plus 3
  • options:选 Comment、Lombok、Model
  • template:选 mybatis-plus-3

根据名称快速生成代码

增 insert 开头
删除 delete 开头
改 update 开头
查 select 开头,by 查询条件,多个条件以 And 或 Or 连接,排序使用 order

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值