千家信息网

mybatisplus复合主键CRUD的示例分析

发表于:2026-11-04 作者:千家信息网编辑
千家信息网最后更新 2026年11月04日,这篇文章主要介绍了mybatisplus复合主键CRUD的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。mybatisplus
千家信息网最后更新 2026年11月04日mybatisplus复合主键CRUD的示例分析

这篇文章主要介绍了mybatisplus复合主键CRUD的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

    mybatisplus 复合主键CRUD

    需求描述

    最近接到个挺有意思的需求,做用户观看学习视频时长的一个数据埋点

    储存用户观看视频时长、记录的接口的调用肯定会特别频繁,因为每间隔指定时间每个用户都会调用,如果在这个接口里直接操作数据库将会给我们的数据库带来一定的压力,在我的代码中是不允许的,而我是这样完成这个需求的:

    首先将用户观看视频的时长、记录存储到阿里云的日志库里,随后以定时器从阿里云的日志库中拉取用户观看视频的数据同步到我们的数据库中。

    而就是最后这一步,同步数据到数据库中,这里的数据量肯定是庞大的,所以我做了分表。

    但是尽管做了分表数据量也不少,如果通过自增的主键id去编辑数据那么我在更新数据之前都要先从数据库中查询一次,然后在更新

    在数据量大的情况下依然会给我们数据库造成不少压力,且这个定时器的执行时长将会拉大,这是我不能接受的

    所以直接使用复合主键,以视频id+用户id去批量更新数据,这样就会快很多,然而mybatisplus却仅支持单一主键操作,这就让我刚屡清楚的思路陷入了僵局

    不过还是让我找到了支持复合主键的框架

    mybatisplus-plus

    是不是看起来挺离谱的?啥玩意就plus-plus?别急,让我们来看看代码先
    注意mybatisplus与mybatisplus-plus的版本兼容性

    首先引入jar包

         com.github.jeffreyning     mybatisplus-plus     1.5.1-RELEASE     com.baomidou     mybatis-plus-boot-starter     3.1.0       com.baomidou     mybatis-plus-generator     3.1.0 

    PO对象

    package com.youxue.model.lesson;import com.baomidou.mybatisplus.annotation.TableField;import com.baomidou.mybatisplus.annotation.TableName;import com.fasterxml.jackson.databind.annotation.JsonDeserialize;import com.fasterxml.jackson.databind.annotation.JsonSerialize;import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;import com.github.jeffreyning.mybatisplus.anno.MppMultiId;import com.youxue.sharding.annotation.TableIndex;import com.youxue.sharding.annotation.TableIndices;import com.youxue.sharding.model.BaseShardingPo;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.Data;import lombok.EqualsAndHashCode;import lombok.experimental.Accessors;import java.io.Serializable;import java.time.LocalDateTime;/** * 

    * 用户观看视频时长 *

    * * @author dx * @since 2021/6/22 */@Data@EqualsAndHashCode(callSuper = false)@Accessors(chain = true)@TableName("UserWatchVideoLog")@ApiModel(value="UserWatchVideoLogPo对象", description="用户观看视频时长表")@TableIndices({ @TableIndex(name = "IX_USERID" ,ddl = "CREATE NONCLUSTERED INDEX [IX_USERID] ON UserWatchVideoLog ( [UserId] DESC)" ), @TableIndex(name = "IX_LESSONITEMID_USERID" ,ddl = "CREATE NONCLUSTERED INDEX [IX_LESSONITEMID_USERID] ON UserWatchVideoLog (LessonItemId ASC,UserId ASC)" )})public class UserWatchVideoLogPo implements Serializable, BaseShardingPo { @MppMultiId // 复合主键 @TableField("userId") @ApiModelProperty(value = "用户id") private Integer userId; @TableField("lessonItemId") @ApiModelProperty(value = "子课程id") private Integer lessonItemId; @ApiModelProperty(value = "观看时长 单位秒(s)") @TableField("seconds") private Integer seconds; @ApiModelProperty(value = "科目id") @TableField("subjectId") private Integer subjectId; @ApiModelProperty(value = "视频观看时长 单位秒(s)") @TableField("VideoProgress") private Integer videoProgress; @ApiModelProperty(value = "视频来源 默认 0 ") @TableField("[Resource]") private Integer resource; @ApiModelProperty(value = "类型 默认 0 ") @TableField("[Type]") private Integer type; @ApiModelProperty(value = "创建时间") @TableField("CreateTime") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonDeserialize(using = LocalDateTimeDeserializer.class) @JsonSerialize(using = LocalDateTimeSerializer.class) private LocalDateTime createTime; @ApiModelProperty(value = "修改时间") @TableField("UpdateTime") private LocalDateTime updateTime;}

    @MppMultiId 注解即声明为复合主键,并以@TableField 主键 声明表字段

    Service接口

    package com.youxue.service.lesson;import com.github.jeffreyning.mybatisplus.service.IMppService;import com.youxue.model.lesson.UserWatchVideoLogPo;/** * 

    * 用户观看视频记录 服务类 *

    * * @author dx * @since 2021-06-22 */public interface IUserWatchVideoLogService extends IMppService {}

    Impl类

    package com.youxue.service.lesson.impl;import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;import com.youxue.dao.lesson.UserWatchVideoLogMapper;import com.youxue.model.lesson.UserWatchVideoLogPo;import com.youxue.service.lesson.IUserWatchVideoLogService;import org.springframework.stereotype.Service;/** * 

    * 用户观看视频记录 服务类实现类 *

    * * @author dx * @since 2021/6/22 */@Servicepublic class UserWatchVideoLogServiceImpl extends MppServiceImpl implements IUserWatchVideoLogService {}

    Mapper接口

    package com.youxue.dao.lesson;import com.github.jeffreyning.mybatisplus.base.MppBaseMapper;import com.youxue.model.lesson.UserWatchVideoLogPo;/** * 

    * 用户观看视频记录 Mapper 接口 *

    * * @author dx * @since 2021-06-22 */public interface UserWatchVideoLogMapper extends MppBaseMapper {}

    service 继承 IMppService ,mapper 继承 MppBaseMapper,impl 继承 MppServiceImpl 实现 service

    并在启动类上添加 @EnableMPP 注解

    随后直接在测试用例中运行(测试用例中未使用分表):

    @Autowiredprivate IUserWatchVideoLogService userWatchVideoLogService;@Testpublic void testUserWatchVideo() {        UserWatchVideoLogPo userWatchVideoLogPo = new UserWatchVideoLogPo()                .setUserId(6202238)                .setLessonItemId(56303)                .setSeconds(8888)                .setResource(11);        boolean create = userWatchVideoLogService.save(userWatchVideoLogPo);        System.out.println(create);        System.out.println("create result :" + create);        System.out.println("================ create end ==================");                // 断点01        UserWatchVideoLogPo watchVideoLogPo = userWatchVideoLogService.selectByMultiId(userWatchVideoLogPo);        System.out.println(watchVideoLogPo.toString());        System.out.println("================ retrieve end ==================");        userWatchVideoLogPo.setSeconds(99999);        userWatchVideoLogPo.setResource(22);                        // 断点03                boolean upd = userWatchVideoLogService.updateByMultiId(userWatchVideoLogPo);        System.out.println("upd result :" + upd);        System.out.println("================ update end ==================");        // 断点03        boolean remove = userWatchVideoLogService.deleteByMultiId(userWatchVideoLogPo);        System.out.println("remove result :" + remove);        System.out.println("================ remove end ==================");}

    我在save 方法后每个方法出都打了断点,下面我们来看看运行结果

    可以看到,添加方法打印的SQL与mybatisplus并没有什么区别,随后看一下数据库中的数据

    是正常的,我们来看一下查询操作

    可以看到,这里的where条件后跟的是两个查询条件,是不是很棒。再看看编辑操作

    可以到编辑操作的SQL也是已两个条件操作的,数据也更新过来了,最后删除操作:

    至此支持复合组件的CRUD就完成了

    而 mybatisplus-plus 作为 mybatisplus 的升级版 新颖的功能肯定不止于此

    根据多个字段联合主键增删改查

    原生mybatisplus只支持一个主键,

    mpp支持多个字段联合主键(复合主键)增删改查,

    mapper需要继承MppBaseMapper
    实体类中联合主键的字段需要用@MppMultiId注解修饰
    如果需要在service使用多主键相关操作包括saveOrUpdateByMultiId和批量操作

    updateBatchByMultiId和saveOrUpdateBatchByMultiId,可以直接继承IMppService接口

    优化分页插件实现在不分页时进行排序操作

    原生mybatisplus分页与排序是绑定的,mpp优化了分页插件,使用MppPaginationInterceptor插件
    在不分页的情况下支持排序操作
    page参数size设置为-1可实现不分页取全量数据,同时设置OrderItem可以实现排序

    自动填充优化功能 & 自动扫描Entity类构建ResultMap功能

    原生mybatisplus只能做%s+1和now两种填充,mybatisplus-plus在插入或更新时对指定字段进行自定义复杂sql填充。
    需要在实体类字段上用原生注解@TableField设置fill=FieldFill.INSERT fill=FieldFill.UPDATE或fill=FieldFill.INSERT_UPDATE否则不会触发自定义填充
    mybatisplus-plus使用@InsertFill注解触发插入时,执行注解中自定义的sql填充实体类字段
    mybatisplus-plus使用@UpdateFill注解触发更新时,执行注解中自定义的sql填充实体类字段
    还可以自动填充主键字段,解决原生mybatisplus不支持多个主键的问题
    使用ColNameUtil.pn静态方法,获取实体类中读取方法对应的列名称

    感谢你能够认真阅读完这篇文章,希望小编分享的"mybatisplus复合主键CRUD的示例分析"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

    数据 用户 视频 字段 时长 注解 支持 数据库 接口 更新 实体 方法 篇文章 排序 分表 功能 多个 插件 断点 时间 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网与科技金融数据 互联网 科技 互联网金融 金融科技 互联网 的科技创新 互联网金融科技平台 互联网科技上市公司 睿民互联网科技 天扬科技互联网广告 上海电发互联网科技有限公司 哈尔滨新华互联网科技学院 速维有品互联网信息科技(苏州)有限公司 乌苏新华互联网科技做什么的 中国科技创新与世界互联网大会 恒生互联网科技业指数调整周期 国大互联网教育科技有限公司薪资 杭州披云加互联网科技有限公司 互联网科技快讯热点 南京一网一红互联网科技有限公司 云南互联网科技学费 高科技和互联网的现代国家 互联网巨头科技公司 北京禾田雨橡互联网科技 大白互联网科技 华服互联网科技官网 互联网金融科技展 互联网公司黑科技创始人 朱啸虎曾投资哪些互联网科技企业 兰石爱特工业互联网科技分公司 互联网科技创业计划的风险分析 互联网科技创业有什么好项目
    0