本文主要介绍 MyBatis 一对一和一对多相关使用,还有就是分页的简单介绍。
之前我在做文章列表,如下图1这种后台文章列表的时候,通常都是从数据库将文章表查出来,然后遍历往文章列表里填用户信息、分类列表信息、标签信息
我们发现这种写法,如果按照一页显示10篇文章,需要查询数据库(在不用redis缓存情况下) 1+10+10+10 = 31 次,这个消耗是很多的,光数据库往返消耗就不少。
基于上面的痛点,我们不得不考虑减少数据库查询,即便是关联查询需要关联5张表,一条SQL语句需要查询6张表,我们也要考虑一下。
just do it!
一篇文章通常只有一个用户,多个分类,多个标签。
直接用 navicat 查看几张表的结构,从左到右,自上而下分别是 用户表、文章表、分类表、标签表、文章和标签关联表、文章和分类关联表
文章实体类
Post.java
这里使用Mybatis-plus
PostMapper.java
PostMapper.xml
association 是一对一的关键字,collection是一对多的关键字
这里说明一下
一对多会导致分页出现数据缺失,比如我们目前有20篇文章,每篇文章都有1到两个分类和标签,这会导致查出100条数据,然后如果直接LIMIT 0,10 会导致最终的文章表只有三五个记录。
所以我们需要如shang'm'd
一、背景
之前我在做文章列表,如下图1这种后台文章列表的时候,通常都是从数据库将文章表查出来,然后遍历往文章列表里填用户信息、分类列表信息、标签信息
图1 文章后台图示例图
代码 实现如下
- for (Post p : page.getRecords()) {
- //封装分类,标签,用户详细信息
- List<Category> categories = categoryService.findByPostId(p.getId());
- List<Tag> tags = tagService.findByPostId(p.getId());
- User user = userService.get(p.getId());
- p.setCategories(categories);
- p.setTags(tags);
- p.setUser(user);
- }
我们发现这种写法,如果按照一页显示10篇文章,需要查询数据库(在不用redis缓存情况下) 1+10+10+10 = 31 次,这个消耗是很多的,光数据库往返消耗就不少。
基于上面的痛点,我们不得不考虑减少数据库查询,即便是关联查询需要关联5张表,一条SQL语句需要查询6张表,我们也要考虑一下。
just do it!
二、文章、分类、标签和用户的关系
一篇文章通常只有一个用户,多个分类,多个标签。
直接用 navicat 查看几张表的结构,从左到右,自上而下分别是 用户表、文章表、分类表、标签表、文章和标签关联表、文章和分类关联表
文章实体类
Post.java
- package com.liuyanzhao.sens.modules.blog.entity;
- import com.baomidou.mybatisplus.annotations.TableField;
- import com.baomidou.mybatisplus.annotations.TableId;
- import com.baomidou.mybatisplus.annotations.TableName;
- import com.fasterxml.jackson.annotation.JsonFormat;
- import com.liuyanzhao.sens.common.constant.CommonConstant;
- import com.liuyanzhao.sens.common.utils.SnowFlakeUtil;
- import lombok.Data;
- import org.springframework.format.annotation.DateTimeFormat;
- import java.util.Date;
- import java.util.List;
- /**
- * @author 言曌
- */
- @Data
- @TableName("t_blog_post")
- public class Post {
- private static final long serialVersionUID = 1L;
- @TableId
- private String id = String.valueOf(SnowFlakeUtil.getFlowIdInstance().nextId());
- /**
- * 用户ID
- */
- private String userId;
- /**
- * 文章标题
- */
- private String title;
- /**
- * 文章类型
- * post 文章
- * page 页面
- */
- private String type = "post";
- /**
- * 文章内容 html格式
- */
- private String content;
- /**
- * 文章路径
- */
- private String url;
- /**
- * 文章摘要
- */
- private String summary;
- /**
- * 缩略图
- */
- private String thumbnail;
- /**
- * 0 已发布
- * 1 草稿
- * 3 待审核
- * 4 回收站
- */
- private Integer status = 0;
- /**
- * 文章访问量
- */
- private Long views;
- /**
- * 点赞访问量
- */
- private Long likes;
- /**
- * 评论数量(冗余字段,加快查询速度)
- */
- private Long comments;
- /**
- * 文章来源(原创1,转载2,翻译3)
- */
- private Integer source = 1;
- /**
- * 是否允许评论(允许1,禁止0)
- */
- private Integer commentFlag = 1;
- private String createBy;
- @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private Date createTime;
- private String updateBy;
- @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
- @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private Date updateTime;
- /**
- * 删除标志 默认0正常, 1删除
- */
- private Integer delFlag = CommonConstant.STATUS_NORMAL;
- @TableField(exist = false)
- private List<Category> categories;
- @TableField(exist = false)
- private List<Tag> tags;
- @TableField(exist = false)
- private User user;
- }
三、Mapper
这里使用Mybatis-plus
PostMapper.java
- package com.liuyanzhao.sens.modules.blog.dao.mapper;
- import com.baomidou.mybatisplus.mapper.BaseMapper;
- import com.liuyanzhao.sens.modules.blog.dto.PageDto;
- import com.liuyanzhao.sens.modules.blog.entity.Post;
- import org.apache.ibatis.annotations.Param;
- import java.util.List;
- /**
- * @author 言曌
- * @date 2019-06-19 21:06
- */
- public interface PostMapper extends BaseMapper<Post> {
- /**
- * 根据条件查询
- * @param condition 条件
- * @param pageDto 分页封装类
- * @return 文章列表
- */
- List<Post> findByCondition(@Param("condition") Post condition,
- @Param("pageDto") PageDto pageDto);
- }
PostMapper.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="com.liuyanzhao.sens.modules.blog.dao.mapper.PostMapper">
- <resultMap id="postWithCategoriesAndTags" type="com.liuyanzhao.sens.modules.blog.entity.Post">
- <id column="id" property="id"/>
- <result column="create_by" property="createBy"/>
- <result column="create_time" property="createTime"/>
- <result column="del_flag" property="delFlag"/>
- <result column="update_by" property="updateBy"/>
- <result column="update_time" property="updateTime"/>
- <result column="comment_flag" property="commentFlag"/>
- <result column="comments" property="comments"/>
- <result column="content" property="content"/>
- <result column="likes" property="likes"/>
- <result column="source" property="source"/>
- <result column="status" property="status"/>
- <result column="summary" property="summary"/>
- <result column="thumbnail" property="thumbnail"/>
- <result column="title" property="title"/>
- <result column="type" property="type"/>
- <result column="url" property="url"/>
- <result column="views" property="views"/>
- <result column="user_id" property="userId"/>
- <association property="user" javaType="com.liuyanzhao.sens.modules.base.entity.User">
- <id column="user_id" property="id"/>
- <result column="user_username" property="username"/>
- <result column="user_nickName" property="nickName"/>
- <result column="user_avatar" property="avatar"/>
- </association>
- <collection property="categories" ofType="com.liuyanzhao.sens.modules.blog.entity.Category">
- <id column="category_id" property="id"/>
- <result column="category_title" property="title"/>
- </collection>
- <collection property="tags" ofType="com.liuyanzhao.sens.modules.blog.entity.Tag">
- <id column="tag_id" property="id"/>
- <result column="tag_title" property="title"/>
- </collection>
- </resultMap>
- <!-- 文章主要字段:不包括文章内容 -->
- <sql id="mainPostColumns">
- id, user_id, create_by, create_time, comment_flag, comments,
- likes, source, status, summary, thumbnail, title, `type`, url, views
- </sql>
- <!-- 文章主要字段:不包括文章内容 -->
- <sql id="mainPostColumnsWithTable">
- post.id, post.user_id, post.create_by, post.create_time, post.comment_flag,
- post.comments, post.likes, post.source, post.status, post.summary, post.thumbnail,
- post.title, post.`type`, post.url, post.views
- </sql>
- <select id="findByCondition" resultMap="postWithCategoriesAndTags">
- SELECT <include refid="mainPostColumnsWithTable"/>,
- category.id as category_id, category.title as category_title,
- tag.id as tag_id, tag.title as tag_title
- FROM (
- SELECT <include refid="mainPostColumns"/> FROM t_blog_post
- <where>
- del_flag = 0
- <if test="condition.userId != null and condition.userId != ''">
- AND user_id = #{condition.userId}
- </if>
- <if test="condition.title != null and condition.title != ''">
- AND title LIKE CONCAT('%','${condition.title}','%')
- </if>
- <if test="condition.status != null and condition.status != ''">
- AND status = #{condition.status}
- </if>
- <if test="condition.source != null and condition.source != ''">
- AND source = #{condition.source}
- </if>
- <if test="searchDate.startDate != null and searchDate.startDate != ''">
- AND create_time >= #{searchDate.startDate}
- </if>
- <if test="searchDate.endDate != null and searchDate.endDate != ''">
- AND create_time <= #{searchDate.endDate}
- </if>
- </where>
- LIMIT #{pageDto.from}, #{pageDto.pageSize}) post
- LEFT JOIN t_blog_post_category as post_category ON post.id = post_category.post_id
- LEFT JOIN t_blog_category as category ON post_category.category_id = category.id
- LEFT JOIN t_blog_post_tag as post_tag ON post.id = post_tag.post_id
- LEFT JOIN t_blog_tag as tag ON post_tag.tag_id = tag.id
- LEFT JOIN t_user as user ON post.user_id = user.id
- </select>
- </mapper>
association 是一对一的关键字,collection是一对多的关键字
这里说明一下
一对多会导致分页出现数据缺失,比如我们目前有20篇文章,每篇文章都有1到两个分类和标签,这会导致查出100条数据,然后如果直接LIMIT 0,10 会导致最终的文章表只有三五个记录。
所以我们需要如shang'm'd
您可以选择一种方式赞助本站
支付宝扫一扫赞助
微信钱包扫描赞助
赏