mybatis-plus学习笔记


前言

文中controller中的返回类是我自定义的,源码中有,我的另一篇文章也有返回类,源码中还有文中表和数据的sql
源码地址:mybatis-plus

一、springboot和mybatis-plus整合

1、依赖


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

2、配置文件

# 应用名称
spring:
  application:
    name: mybatis-plus
  datasource:
    driver-class-name: com.mysql.cj.jdbc.NonRegisteringDriver
    url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
    username: root
    password: 123456

server:
  port: 8782

#指定Mybatis的Mapper文件
mybatis:
  mapper-locations: classpath:mappers/*xml

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #日志打印

3、启动类

启动类加@MapperScan注解,里面的内容为你自己mapper层接口的包。

@SpringBootApplication
@MapperScan("com.sofar.mybatisplus.mapper")
public class MybatisPlusApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusApplication.class, args);
    }
}

4、service接口,service实现类,mapper

mybatis-plus跟我们平时写的项目结构一样,由service到service实现类,到mapper。
service:IService
service实现类:ServiceImpl<M extends BaseMapper, T>
mapper:BaseMapper

  mybatis-plus提供这几个都是泛型类,对应的泛型是我们要操作的的表对应的实体类,我们要操作一个表对应下来的service,service实现类,mapper的泛型都应该是同一个类。
1、service

public interface TblProductService extends IService<TblProduct> {
    /**
     * 分页查询
     * @param tblProduct
     * @param iPage
     * @return
     */
    IPage<TblProduct> queryByPage(TblProduct tblProduct, IPage<TblProduct> iPage);

}

2、service实现类
  当你service实现类继承了ServiceImpl<M extends BaseMapper, T>后,会提示你要实现接口方法,但是你自己的接口明明实现了。不要着急,那是因为ServiceImpl依赖于BaseMapper,ServiceImpl<M extends BaseMapper, T>里面已经明确指出要继承BaseMapper,在mapper接口中去继承就好了,请看下一步。
  这里有个小故事分享给大家,是我在工作中发现的,我们项目也用了mybatis-plus,有一个同事在写service和service实现类的时候,他mapper没有继承BaseMapper,而是在service实现类中去实现mybatis-plus的接口的方法,但是他只是实现了接口方法,并没有在方法里面写业务代码。相当于是他只是让报错消失,并没有解决问题。有一次我在控制层中调用mybatis-plus service 自带的方法新增数据,一直失败,我一直以为是数据原因,到后面才发现是没有service实现类中的新增数据方法是空,没有想到自带的方法被他实现了,但方法里没有具体实现,是空方法,导致新增失败,吐血。
  提醒:继承的mybatis-plus的类后,不能跟基类的方法名一直,不然就是方法覆盖。自己真的想覆盖,可以写,不要搞出我上面陈诉的那种情况。

@Service("tblProductService")
public class TblProductServiceImpl extends ServiceImpl<TblProductMapper,TblProduct> implements TblProductService {
    @Resource
    private TblProductMapper tblProductMapper;
    
    @Override
    public IPage<TblProduct> queryByPage(TblProduct tblProduct, IPage<TblProduct> iPage) {
        return tblProductMapper.queryAllByPage(tblProduct, iPage);
    }
}

3、mapper

public interface TblProductMapper extends BaseMapper<TblProduct> {

    /**
     * 分页查询
     * @param tblProduct
     * @param iPage
     * @return
     */
    IPage<TblProduct> queryAllByPage(@Param("req") TblProduct tblProduct, IPage<TblProduct> iPage);
}

二.枚举类型处理及遇到坑解决

  开发中我们经常用到枚举,例如性别,前端我们需要展示男、女,而数据库我们存的是1、0。

一、创建枚举类,在需要存储数据库的属性上添加@EnumValue注解,在需要前端展示的属性上添加@JsonValue注解;
  @JsonValue可以用在get方法或者属性字段上,一个类只能用一个,当加上@JsonValue注解时,该类的json化结果,只有这个get方法的返回值,而不是这个类的属性键值对.

public enum SexEnum {
    /**
     * 女
     */
    WOMAN(0,"女"),

    /**
     * 男
     */
    MAN(1, "男");

    @EnumValue
    private Integer code;

    @JsonValue
    private String value;

    SexEnum(int code, String value){
        this.code = code;
        this.value = value;
    }

    public Integer getCode(){
        return this.code;
    }

    public String getValue(){
        return this.value;
    }
}

二、配置文件

#配置枚举 支持通配符 * 或者 ; 分割
mybatis-plus:
  configuration:
    default-enum-type-handler: org.apache.ibatis.type.EnumOrdinalTypeHandler
  type-enums-package: com.sofar.mybatisplus.enums  #扫描枚举包

三、将实体类中的sex属性设置为枚举SexEnum;

    /**
     * 性别:0:女、 1:男
     */
    private SexEnum sex;

四、遇到的问题
  刚开始我数据库表中sex字段类型为tinyint,而SexEnum枚举中带@EnumValue注解的属性类型为Integer(如下面两张图所示),数据类型不一致,导致无法转换。调用接口sex字段一直为null,后面我将数据库字段类型换成int类型,才转换成功。@EnumValue注解是放在与数据库表字段对应的属性上,而且要保证与数据库字段类型要一致,才能转换成功
在这里插入图片描述
在这里插入图片描述

五、测试

  controller中直接调用mybatis-plus自带的getById(id)方法。没有任何的业务处理,直接查库

    /**
     * 通过id查询
     * @param id
     * @return
     */
    @GetMapping("getById/{id}")
    public AjaxResult getById(@PathVariable("id") Long id){
        TblUser byId = tblUserService.getById(id);
        return Result.success(byId);
    }

数据库数据,性别存了0、1
在这里插入图片描述
调用接口结果,自动将数据库的0、1转换成女、男
在这里插入图片描述

三.字段自动填充及问题解决

  在开发中我们的表通常都会有创建时间、创建人、更新时间、更新人这几个字段,通常各个表都会统一这些字段的名称和类型。在我们新增各个表的数据的时候,都需要手动去维护这些字段,显得很麻烦、冗余,mybatis-plus提供了字段自动填充功能,帮我们解决了这一问题。

1、字段加注解
  @TableField是字段注解(非主键),fill(字段自动填充策略),共有四种。DEFAULT、INSERT、UPDATE、INSERT_UPDATE,策略含义跟命名一致

 /**
     * 创建时间
     */
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

2、自定义实现类 MyMetaObjectHandler

package com.sofar.mybatisplus.config;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @author 
 * @version 1.0.0
 * @ClassName MyMetaObjectHandler
 * @Description TODO
 * @createTime 2022年08月31日 15:42:00
 */
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
//        判断是否存在该字段,有的表没有,没有不用执行填充代码,避免资源浪费
        boolean createTime = metaObject.hasSetter("createTime");
        boolean updateTime = metaObject.hasSetter("updateTime");
        log.info("start insert fill ....");
        if (createTime){
//            填充的类型要和实体类的类型要一致,例如实体类是Date,填充是LocalDateTime,最后填充结果为null
            this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
        }
        if (updateTime){
            this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
        }

    }

    /**
     * 
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        boolean updateTime = metaObject.hasSetter("updateTime");
        if (updateTime){
            log.info("start update fill ....");
            this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
        }

    }
}

3、遇到问题
我的实体类中创建时间的类型是Date,如下。

 /**
     * 创建时间
     */
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

而我参照的是mybatis-plus的官方文档,然后copy过来,

this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());

结果:没有自动填充成功,因为实体类的创建时间类型为Date,而我填充的是LocalDateTime。类型不一致,无法自动填充。

四、多数据源

1、依赖

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

2、配置文件

# 应用名称
spring:
  application:
    name: mybatis-plus
  datasource:
    dynamic:
      primary: master  #设置默认的数据源或者数据源组,默认值即为master
      strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      datasource:
        master:
          driver-class-name: com.mysql.cj.jdbc.NonRegisteringDriver
          url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
          username: root
          password: 123456
        slave_1:
          driver-class-name: com.mysql.cj.jdbc.NonRegisteringDriver
          url: jdbc:mysql://localhost:3306/test2?serverTimezone=UTC
          username: root
          password: 123456

server:
  port: 8782

#指定Mybatis的Mapper文件
mybatis:
  mapper-locations: classpath:mappers/*xml

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3、@DS注解
  @DS注解可以放在类上,也可以放在方法上,当放在类上,数据源作用在类上(即类中所有方法都使用该数据源),放在方法上,数据源作用在方法上,当类和方法都有@DS注解,以方法的数据源为主。

@Service("tblUserService")
public class TblUserServiceImpl extends ServiceImpl<TblUserMapper,TblUser> implements TblUserService {

    @Resource
    private TblUserMapper tblUserMapper;

    @DS("master")
    @Override
    public TblUser queryById(Long id) {
        return this.getById(id);
    }
}

4、测试

(1)、数据准备
准备两个数据库,我这里是test,test2,test中的tbl_user有两条数据,id分别为1、2,test2中有一条数据id为3
在这里插入图片描述
test
在这里插入图片描述
test2
在这里插入图片描述

(2)测试master数据源
controller

@RestController
@RequestMapping("tblUser")
public class TblUserController {
    /**
     * 服务对象
     */
    @Resource
    private TblUserService tblUserService;
    /**
     * 通过id查询
     * @param id
     * @return
     */
    @GetMapping("getById/{id}")
    public AjaxResult getById(@PathVariable("id") Long id){
        TblUser byId = tblUserService.queryById(id);
        return Result.success(byId);
    }
}

service

public interface TblUserService extends IService<TblUser> {
    /**
     * 通过id查询单条数据
     * @param id
     * @return
     */
    TblUser queryById(Long id);
}

serviceImpl

@Service("tblUserService")
public class TblUserServiceImpl extends ServiceImpl<TblUserMapper,TblUser> implements TblUserService {

    @Resource
    private TblUserMapper tblUserMapper;

    @DS("master")
    @Override
    public TblUser queryById(Long id) {
        return this.getById(id);
    }
}

结果:查询到了id为1的数据
在这里插入图片描述
(3)查询slave_1数据源
其他层跟测试master数据源一样,serviceImpl方法上的@DS注解修改成slave_1数据源

@Service("tblUserService")
public class TblUserServiceImpl extends ServiceImpl<TblUserMapper,TblUser> implements TblUserService {

    @Resource
    private TblUserMapper tblUserMapper;

    @DS("slave_1")
    @Override
    public TblUser queryById(Long id) {
        return this.getById(id);
    }
}

结果:查询到id为3的数据
在这里插入图片描述

至此测试完成,多数据源配置成功

五、后话

这是我个人的学习笔记,有错望指出!谢谢!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值