本文主要介绍 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

                            
                                


                
您可以选择一种方式赞助本站
支付宝扫一扫赞助
微信钱包扫描赞助
赏