微服务学习系列六:MyBatis-Plus用法

系列文章目录


目录

系列文章目录

前言

一、环境准备

一、为什么要使用utf8mb4字符集

 二、依赖准备

 三、配置准备

二、使用步骤

@TableName

@TableId 主键注解

IdType

@TableField

实体类UserInfoDO

Mapper层CRUD

Service层CRUD 

分页

多数据源 

 @DS注解

 动态表名插件DynamicTableNameInnerInterceptor

总结


前言

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

一、环境准备

本文基于Spring Boot、maven、jdk1.8、mySQL开发,所以开始前我们需要准备好这套环境。

mySQL 数据表 我采用utf8mb4这种字符集,做过微信的同学应该会知道,微信用户名称的表情,是需要这种字符集才能存储的。

一、为什么要使用utf8mb4字符集

低版本的MySQL支持的utf8编码,最大字符长度为 3 字节,如果遇到 4 字节的字符就会出现错误了。三个字节的 UTF-8 最大能编码的 Unicode 字符是 0xFFFF,也就是 Unicode 中的基本多文平面(BMP)。也就是说,任何不在基本多文平面的 Unicode字符,都无法使用MySQL原有的 utf8 字符集存储。这些不在BMP中的字符包括哪些呢?最常见的就是Emoji 表情(Emoji 是一种特殊的 Unicode 编码,常见于 ios 和 android 手机上)和一些不常用的汉字,以及任何新增的 Unicode 字符等等。
那么utf8mb4比utf8多了什么的呢?
✔ 多了emoji编码支持
如果实际用途上来看,可以给要用到emoji的库或者说表,设置utf8mb4,比如评论要支持emoji可以用到。
 

 二、依赖准备

         <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-dependencies</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

         <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>

         <!-- mybatis-plus 多数据源 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.5.0</version>
        </dependency>

 三、配置准备

Spring Boot启动类。配置@MapperScan注解,用于扫描Mapper文件位置:

/**
 * 用户微服务启动类
 *
 * @author yangyanping
 * @date 2022-02-28
 */
@SpringBootApplication
@EnableTransactionManagement
@ComponentScan("com.yyp.user")
@MapperScan("com.yyp.user.infra.gatewayImpl.database")
public class WebApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebApplication.class);
    }
}

二、使用步骤

mybatis-plus为使用者封装了很多的注解,方便我们使用,我们首先看下实体类中有哪些注解。

@TableName

表名注解,用于标识实体类对应的表,使用位置:实体类。

属性 类型 必须指定 默认值 描述
value String "" 表名
schema String "" schema
keepGlobalPrefix boolean false 是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时)
resultMap String "" xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定)
autoResultMap boolean false 是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入)
excludeProperty String[] {} 需要排除的属性名 @since 3.3.1

@TableId 主键注解

属性性 类型 必须指定 默认值 描述
value String "" 主键字段名
type Enum IdType.NONE 指定主键类型

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 方法)
ID_WORKER 分布式全局唯一 ID 长整型类型(please use ASSIGN_ID)
UUID 32 位 UUID 字符串(please use ASSIGN_UUID)
ID_WORKER_STR 分布式全局唯一 ID 字符串类型(please use ASSIGN_ID)

@TableField

属性 类型 必须指定 默认值 描述
value String "" 数据库字段名
exist boolean true 是否为数据库表字段
condition String "" 字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s}参考(opens new window)
update String "" 字段 update set 部分注入,例如:当在version字段上注解update="%s+1" 表示更新时会 set version=version+1 (该属性优先级高于 el 属性)
insertStrategy Enum FieldStrategy.DEFAULT 举例:NOT_NULL
insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
updateStrategy Enum FieldStrategy.DEFAULT 举例:IGNORED
update table_a set column=#{columnProperty}
whereStrategy Enum FieldStrategy.DEFAULT 举例:NOT_EMPTY
where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
fill Enum FieldFill.DEFAULT 字段自动填充策略
select boolean true 是否进行 select 查询
keepGlobalFormat boolean false 是否保持使用全局的 format 进行处理
jdbcType JdbcType JdbcType.UNDEFINED JDBC 类型 (该默认值不代表会按照该值生效)
typeHandler Class<? extends TypeHandler> UnknownTypeHandler.class 类型处理器 (该默认值不代表会按照该值生效)
numericScale String "" 指定小数点后保留的位数

实体类UserInfoDO

/**
 * 用户信息表
 *
 * @author yangyanping
 * @date 2022-11-17
 */
@Getter
@Setter
@TableName("user_info")
public class UserInfoDO {

    /**
     * 主键ID,递增
     */
    @TableId(type = IdType.AUTO)
    private Integer id;

    /**
     * 用户昵称
     */
    private String userName;

    /**
     * 用户状态(0启用,1停用,2 注销中)
     */
    private Integer status;

    /**
     * 用户手机号
     */
    private String mobile;

    /**
     * 用户密码
     */
    private String password;
}

Mapper层CRUD

代码如下(示例):

/**
 * 用户信息表
 *
 * @author yangyanping
 * @date 2023-03-18
 */
@DS("user")
public interface UserInfoMapper extends BaseMapper<UserInfoDO> {
}

Service层CRUD 

/**
 * 用户服务接口
 *
 * @author yangyanping
 * @date 2023-03-18
 */
public interface UserInfoService extends IService<UserInfoDO> {
}

Service 实现层 

/**
 * 用户服务实现类
 *
 * @author yangyanping
 * @date 2023-03-18
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfoDO> implements UserInfoService {
}

分页

分页插件 PaginationInnerInterceptor,使用分页话需要增加分页插件的配置。

Page

该类继承了 IPage 类,实现了 简单分页模型 如果你要实现自己的分页模型可以继承 Page 类或者实现 IPage 类

/**
 * MyBatis Plus 配置类
 *
 * @author yangyanping
 * @date 2023-03-18
 */
public class MyBatisPlusConfig {
    /**
     * 插件集合
     */
    @Bean
    @ConditionalOnMissingBean(MybatisPlusInterceptor.class)
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        //  插件
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 分页插件
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MARIADB);
        // 添加分页插件
        interceptor.addInnerInterceptor(paginationInnerInterceptor);

        return interceptor;
    }
}

如果返回类型是 IPage 则入参的 IPage 不能为null,因为 返回的IPage == 入参的IPage; 如果想临时不分页,可以在初始化IPage时size参数传 <0 的值;
如果返回类型是 List 则入参的 IPage 可以为 null(为 null 则不分页),但需要你手动 入参的IPage.setRecords(返回的 List);
如果 xml 需要从 page 里取值,需要 page.属性 获取 


多数据源 

多数据源既动态数据源,项目开发逐渐扩大,单个数据源、单一数据源已经无法满足需求项目的支撑需求。

使用方法

  • 引入dynamic-datasource-spring-boot-starter。
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
  <version>${version}</version>
</dependency>
  • 配置数据源
spring:
  datasource:
    dynamic:
      primary: book  #设置默认的数据源或者数据源组,默认值即为book
      strict: false  #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      datasource:
        book:
          url: jdbc:mysql://172.0.0.1:3306/book?zeroDateTimeBehavior=convertToNull&autoReconnect=true&generateSimpleParameterMetadata=true
          username: root
          password: root
        user:
          url: jdbc:mysql://172.0.0.41:3306/user?zeroDateTimeBehavior=convertToNull&autoReconnect=true&generateSimpleParameterMetadata=true
          username: root
          password: root
  • 使用 @DS 切换数据源

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

注解 结果
没有@DS 默认数据源
@DS("dsName") dsName可以为组名也可以为具体某个库的名称
/**
 * 用户信息表
 *
 * @author yangyanping
 * @date 2023-03-18
 */
@DS("user")
public interface UserInfoMapper extends BaseMapper<UserInfoDO> {
}

 动态表名插件DynamicTableNameInnerInterceptor

注意事项:

  • 原理为解析替换设定表名为处理器的返回表名,表名建议可以定义复杂一些避免误替换
  • 例如:真实表名为 user 设定为 mp_dt_user 处理器替换为 user_2019 等
  • 动态表名处理器 
/**
 * 动态表名处理器
 * mybatis-plus提供了动态表名处理器接口TableNameHandler,
 * 只需要在系统中实现该接口,并作为插件加载到mybatis-plus中就可以使用
 *
 * @author yangyanping
 * @date 2023-02-15
 */
public class DateTableNameHandler implements TableNameHandler {
    @Override
    public String dynamicTableName(String sql, String tableName) {
        // 模拟获取月份参数,实际应该从参数中获取
        String spiltName =  DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);;
        String dynamicTableName = "user_" + spiltName;

        return dynamicTableName;
    }
}
  • 注册动态表名拦截器 
/**
 * @author miemie
 * @since 2018-08-10
 */
@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor());

        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MARIADB);
        interceptor.addInnerInterceptor(paginationInnerInterceptor);

        return interceptor;
    }


        /**
     * 注册动态表名拦截器
     *
     * @return 动态表名拦截器
     */
    private DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor() {
        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor =
                new DynamicTableNameInnerInterceptor();

        Map<String, TableNameHandler> tableNameHandlerMap = new HashMap<>();

        TableNameHandler tableNameHandler = new DateTableNameHandler();
        tableNameHandlerMap.put("testing_put_in_data", tableNameHandler); // order_tbl表配置动态表名插件
        dynamicTableNameInnerInterceptor.setTableNameHandlerMap(tableNameHandlerMap);

        return dynamicTableNameInnerInterceptor;
    }
}

MyBatis-Plus打印日志

在 logback.xml 中 自定义logger ,日志级别设置为 degug 

    <!-- 自定义logger -->
    <logger name="com.yyp.user.infra.gatewayImpl.database.user" level="debug" additivity="false">
        <appender-ref ref="file-all"/>
    </logger>

总结

以上主要是对MyBatis-Plus 在日常开发中做下总结和记录。

参考:

简介 | MyBatis-Plus

卷王必备学习的MyBatis-Plus用法,不来瞧瞧吗~~-阿里云开发者社区

MyBatisPlus如何进行分表查询? - 知乎

猜你喜欢

转载自blog.csdn.net/yangyanping20108/article/details/129348185