logo 范 · 拾光录
网址收集 关于作者 Github Gitee
杂文随笔5
Hexo博客:基础使用Hexo博客:Next主题Hexo博客:Next进阶使用Hexo博客:Next高级配置基于Node的WIKI管理
前端知识16
HTML常用知识CSS常用知识CSS美化checkbox复选框JavaScript常用知识JavaScript格式化时间戳JavaScript窗口宽高处理JavaScript黑夜主题切换实现方案JavaScript数字转大写简易图片查看器TypeScript基础知识Threejs基础三要素Threejs网格辅助和轨道控制器Threejs物体绘制Electron基础使用Nodejs基础知识animate.css页面动画
Vue框架19
Vite的使用及扩展Vue3父子组件Vue3使用Marked解析MarkdownMermaid图表生成库初始化页面加载动画Axios表单提交二维码解决方案NProgress加载进度条Vue3动态菜单实现Vue3使用ECharts图表Vue3处理Excel导入导出keep-alive页面缓存及setup问题Element:文件上传Element:结合Pinia实现动态菜单Element:图片上传组件Element:自定义统一弹窗组件Element:表格自定义指令控制按钮显示(鉴权)可视化大屏使用缩放适配分辨率
UniApp15
UniApp的基础使用封装网络请求工具及文件上传uni-app的开发记录微信小程序分享原生文件上传Pinia取消滚动条(兼容小程序)tabbar消息数量显示scroll-view上滑到底部加载数据状态栏高度动态设配数据共享与传递uview-plus导航栏实现背景融合Wot UIWot UI实现顶部背景图融合uni-app x
Java基础知识10
基础知识面向对象Lambda表达式常用API常用知识积累try-with-resource注解反射多线程经纬度距离计算
SpringBoot31
application配置Maven创建聚合项目全局异常处理锁机制项目启动初始化数据方式邮件功能集成原生定时任务异步集成阿里云OSS阿里OSS预签名上传基于hutool读excelJSR303WebSocketWebSocket版AI接口流式调用Smart-Doc接口文档生成器application配置信息加密雪花算法工具AOP实现请求参数脱敏思路JWT生成Token及工具类SpringBoot默认JSON与对象转换若依框架:安装使用若依框架:优化和调整文件上传若依框架:管理后台页面优化若依框架:后端接口代码优化SpringAISpringBoot实现AI接口流式调用服务启动时创建MySQL连接自建项目工程树形结构处理工具微信支付代码微信手机号登录
SpringMVC14
跨域处理拦截器RESTful风格伪前后端分离Jackson转换器调整Thymeleaf基于拦截器做权限校验AOP打印接口请求响应日志AOP打印接口请求响应耗时文件上传和回显POST请求加解密实现(AES)POST请求加解密实现(RSA+AES)参数动态校验实现方案真实IP和归属地
MyBatis8
MyBatis基本使用与配置Mapper使用相关MaBatis多数据源配置MyBatisPlus数据统计类处理方案MyBatisPlus条件查询正向工程的实现(H2)mybatis-plus-join
SpringCloud15
Netflix:微服务与搭建Netflix:服务的消费与提供Netflix:EurekaNetflix:ActuatorNetflix:RibbonNetflix:FeignNetflix:HystrixNetflix:ZuulAlibaba:简介与搭建Alibaba:Nacos注册中心Alibaba:RibbonAlibaba:OpenFeignAlibaba:Nacos配置中心Alibaba:GetewayAlibaba:Sentinel
MySQL6
MySQL基础知识MySQL多表查询与事务MySQL常用函数及解决方案MySQL视图MySQL索引安装MySQL
Redis7
Redis介绍和安装Redis配置文件Redis持久化Redis集群Redis语法基础Redis相关问题及解决方案SpringBoot集成Redis使用记录
MongoDB10
Linux安装MongoDBMongoDB基础语法MongoTemplate及SpringBoot配置MongoTemplate中Update操作MongoTemplate中聚合查询MongoTemplate日期归档示例项目使用相关知识归纳地理位置存储与距离查询MongoDB副本集与事务获取类名和属性名工具类
其他数据库1
H2数据库
Python编程6
Python基础知识Python语法yolo目标检测OpenCV的使用及树莓派平台condauv
工具集合13
IDEAMavenGradleGitNginx安装Nginx配置VSCodeJMeter压测DockerOllamaRustFSPicGoObs录制
Linux知识11
Linux常用命令Jar启动脚本VirtualBox安装CentOSVirtualBox安装Ubuntu树莓派安装及使用frp内网穿透ArchLinux:基础系统安装ArchLInux:图形化界面安装ArchLinux:常用软件ArchLinux:深度优化ArchLinux:Niri
创意设计2
Blender:入门知识UI设计基础知识
AI相关9
Claude CodeHermes AgentOpenAI基本使用OpenAI工具调用OpenAI记忆管理OpenAI推理执行OpenAI开发框架Langchainllama.cpp

集成方式

引入依赖,MyBatisPlus依赖了MyBatis,所以MyBatis不用引入了

最新版本可到官网Github仓库查看,可搭配mybatis-plus-join使用,关联查询更方便

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

springboot4.x

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot4-starter</artifactId>
    <version>3.5.15</version>
</dependency>

配置

mybatis-plus:
  configuration:
    # 链接超时时间
    default-statement-timeout: 15
    # 开启驼峰命名规则映射(用于数据返回映射到实体类)
    map-underscore-to-camel-case: true
  # xml路径
  mapper-locations: classpath:mapper/*.xml

记得在启动类上指定扫描包

@MapperScan("com.example.mapper")

将Mapper类都继承BaseMapper并指定实体类

public interface UserMapper extends BaseMapper<User> {

}

然后该Mapper就有了很多基础查询的方法

实体类注解

import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@TableName("user")
public class User {

    /**
     * ID
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 姓名
     */
    @TableField(value = "name")
    private String name;

    /**
     * 年龄
     */
    @TableField(value = "age")
    private Integer age;

    /**
     * 性别:0-男,1-女
     */
    @TableField(value = "sex")
    private Integer sex;

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

    /**
     * 更新时间
     */
    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

    /**
     * 性别:男
     */
    public static final int SEX_MAN = 0;

    /**
     * 性别:女
     */
    public static final int SEX_WOMAN = 1;

    /**
     * 性别显示,数据表中不存在
     */
    @TableField(exist = false)
    private String sexName;

    /**
     * 通过Get处理性别的显示
     */
    public String getSexName() {
        if (sex == null) {
            return "不明";
        } else if (sex == 0) {
            return "男";
        } else if (sex == 1) {
            return "女";
        }
        return "不明";
    }

}

注意:实体类中不要使用基本数据类型,会自动填充,例如使用了int类型字段,在updateById时会更新该字段为0,只有为null的字段才不会更新

IDEA插件

MybatisX是苞米豆提供了一款全免费且强大的IDEA插件,支持跳转,自动补全生成SQL,代码生成

查看SQL日志

只需要将输入日志的级别调整到debug即可

# 日志级别
logging:
  level:
    com.example: debug

主键策略

通过@TableId(value = "id", type = IdType.AUTO)中的IdType可以指定ID的生成策略

类型 说明
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方法)

简单CRUD

/**
 * 添加
 */
@Test
void insert() {
    User user = User.builder()
            .name("张三")
            .age(20)
            .createTime(new Date())
            .build();
    int row = userMapper.insert(user);
    // 可以直接获取到插入成功后的主键
    System.out.println(user.getId());
}

/**
 * 修改
 */
@Test
void update() {
    User user = User.builder()
            .id(1L)
            .name("李四")
            .age(21)
            .updateTime(new Date())
            .build();
    int row = userMapper.updateById(user);
    System.out.println(row);
}

/**
 * 删除
 */
@Test
void delete() {
    int row = userMapper.deleteById(3);
    System.out.println(row);
}

/**
 * 查询
 */
@Test
void query() {
    // 根据ID查询
    User user = userMapper.selectById(1L);
    System.out.println(user);
    // 根据Map条件查询List
    Map<String, Object> userMap = new HashMap<>();
    userMap.put("age", 20);
    List<User> users = userMapper.selectByMap(userMap);
    System.out.println(users);
}

Service CRUD接口

MyBatisPlus提供了很多Service层的通用接口,文档说明

接口定义

import com.baomidou.mybatisplus.extension.service.IService;
import com.example.entity.User;

/**
 * User Service
 * 需要通过泛型指定要操作的实体类
 */
public interface UserService extends IService<User> {

    // 这里写自己定义的方法

}

实现接口

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.User;
import com.example.mapper.UserMapper;
import com.example.service.UserService;
import org.springframework.stereotype.Service;

/**
 * 继承通用ServiceImpl实现,并指定要操作的实体类
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    // 实现自己写方法

}

mapper继承

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fan.entity.Users;

public interface UserMapper extends BaseMapper<Users> {
}

使用方法,需要注意的是,MyBatisPlus在Mapper命名采用的是SQL关键字方式,而Service层采用的是getsave等方式

/**
 * 添加
 */
@Test
void save() {
    User user = User.builder()
            .name("王五")
            .age(18)
            .createTime(new Date())
            .build();
    boolean save = userService.save(user);
    System.out.println("操作状态:" + save + ",ID:" + user.getId());
}

/**
 * 修改
 */
@Test
void saveOrUpdate() {
    User user = User.builder()
            .id(6L)
            .name("王五")
            .age(24)
            .createTime(new Date())
            .build();
    // 根据ID先查询再更新,如果没有ID直接插入
    boolean save = userService.saveOrUpdate(user);
    System.out.println("操作状态:" + save + ",ID:" + user.getId());
}

分页插件

分页的使用需要先配置分页插件,已内置,需要开启,从``开始被分离出来了

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-jsqlparser</artifactId>
</dependency>
// 最新版
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
    return interceptor;
}

示例

/**
 * 分页
 */
public Result<List<Question>> list(@RequestBody @Valid QuestionListReqVo params) {
    // 查询条件
    QueryWrapper<Question> wrapper = new QueryWrapper<>();
    wrapper.lambda().eq(Question::getType, params.getType());
    if (Objects.nonNull(params.getCateId())) {
        wrapper.lambda().eq(Question::getCateId, params.getCateId());
    }
    if (StringUtils.hasLength(params.getKeyword())) {
        wrapper.lambda().like(Question::getTitle, params.getKeyword());
    }
    // 分页
    Page<Question> page = new Page<>();
    page.setSize(params.getPageSize());
    page.setCurrent(params.getPageIndex());
    Page<Question> pageObj = questionService.page(page, wrapper);
    // 列表
    List<Question> list = pageObj.getRecords();
    // 当前页
    long current = pageObj.getCurrent();
    // 页大小
    long size = pageObj.getSize();
    // 总页数
    long pages = pageObj.getPages();
    return Result.data(list);
}

注意Pageindex从1开始

Wapper

在所以需要Wapper的地方都可以,实现更为复杂的操作

QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 可指定查询的字段
queryWrapper.select("id","name")
        // 添加控制
        .eq("name", "张三");
// Lambda方式
queryWrapper.lambda()
        .select(User::getId, User::getName)
        .eq(User::getName, "张三");
List<User> users = userService.list(queryWrapper);
System.out.println(users);

LambdaQueryWrapper

都能以Lambda形式操作,再写字符字段,推荐

LambdaQueryWrapper<Busmanager> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Busmanager::getState, 0);
queryWrapper.eq(Busmanager::getSmsType, 1);
List<Busmanager> list = busmanagerService.list(queryWrapper);

自动填充

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

/**
 * 更新时间
 */
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;

需要配置

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;

/**
 * 自动填充
 */
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("开始插入填充...");
        this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
        this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
    }

}

注意填充类型,官方示例是字符类型,可根据自己的填充类型修改

逻辑删除

https://baomidou.com/guides/logic-delete/

临时禁用逻辑删除

// 禁用逻辑删除过滤
wrapper.disableLogicDel();

or语句

wrapper.like(Article::getName, params.getKeyword())
       .or()
       .like(Article::getContent, params.getKeyword());


// 显式用 and 包裹 OR 条件,确保它作为一个整体参与 AND
wrapper.and(w -> w.isNull(TbPassRecord::getVideoUrlRight)
        .or()
        .isNull(TbPassRecord::getVideoUrl));

单独获取ID

long id = IdWorker.getId();

字段设置为null

LambdaUpdateWrapper<TbUser> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(TbUser::getId, team.getTeamUserId())
        .set(TbUser::getTeamUserId, null);
// 执行更新,第一个参数传 null,因为更新内容已在 wrapper 中定义
tbUserMapper.update(null, updateWrapper);
集成方式
实体类注解
IDEA插件
查看SQL日志
主键策略
简单CRUD
Service CRUD接口
分页插件
Wapper
LambdaQueryWrapper
自动填充
逻辑删除
or语句
单独获取ID
字段设置为null