温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

mybatisplus复合主键CRUD的示例分析

发布时间:2022-03-08 17:22:31 来源:亿速云 阅读:315 作者:小新 栏目:开发技术

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

    mybatisplus 复合主键CRUD

    需求描述

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

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

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

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

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

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

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

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

    mybatisplus-plus

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

    首先引入jar包

    <dependency>
         <groupId>com.github.jeffreyning</groupId>
         <artifactId>mybatisplus-plus</artifactId>
         <version>1.5.1-RELEASE</version>
    </dependency>
    <dependency>
         <groupId>com.baomidou</groupId>
         <artifactId>mybatis-plus-boot-starter</artifactId>
         <version>3.1.0</version>
     </dependency>
     <dependency>
         <groupId>com.baomidou</groupId>
         <artifactId>mybatis-plus-generator</artifactId>
         <version>3.1.0</version>
     </dependency>

    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;
    /**
     * <p>
     *     用户观看视频时长
     * <p/>
     *
     * @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;
    
    /**
     * <p>
     * 用户观看视频记录 服务类
     * </p>
     *
     * @author dx
     * @since 2021-06-22
     */
    public interface IUserWatchVideoLogService extends IMppService<UserWatchVideoLogPo> {
    }

    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;
    
    /**
     * <p>
     * 用户观看视频记录 服务类实现类
     * </p>
     *
     * @author dx
     * @since 2021/6/22 
     */
    @Service
    public class UserWatchVideoLogServiceImpl extends MppServiceImpl<UserWatchVideoLogMapper, UserWatchVideoLogPo> implements IUserWatchVideoLogService {
    }

    Mapper接口

    package com.youxue.dao.lesson;
    
    import com.github.jeffreyning.mybatisplus.base.MppBaseMapper;
    import com.youxue.model.lesson.UserWatchVideoLogPo;
    
    /**
     * <p>
     * 用户观看视频记录 Mapper 接口
     * </p>
     *
     * @author dx
     * @since 2021-06-22
     */
    public interface UserWatchVideoLogMapper extends MppBaseMapper<UserWatchVideoLogPo> {
    }

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

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

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

    @Autowired
    private IUserWatchVideoLogService userWatchVideoLogService;
    
    @Test
    public 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 方法后每个方法出都打了断点,下面我们来看看运行结果

    mybatisplus复合主键CRUD的示例分析

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

    mybatisplus复合主键CRUD的示例分析

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

    mybatisplus复合主键CRUD的示例分析

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

    mybatisplus复合主键CRUD的示例分析

    mybatisplus复合主键CRUD的示例分析

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

    mybatisplus复合主键CRUD的示例分析

    至此支持复合组件的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的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI