下面将讲解MyBatisPlus的联表查询,对于联表查询主要有两种方法:
- 单表查看得到结果再拼接
- 使用JOIN联表
https://juejin.cn/post/7055082744564416542
单表查询实现联表查询
一、一对一/一对多的单条记录查询
1.1创建Model
1.1.1BannerDO
package io.github.talelin.latticy.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
@Getter
@Setter
@TableName("banner")
public class BannerDO {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
private String title;
private String description;
private String img;
@JsonIgnore
private Date createTime;
@JsonIgnore
private Date updateTime;
/* @TableLogic注解参数
value = "" 默认的原值
delval = "" 删除后的值
@TableLogic(value="原值",delval="改值")
* */
@JsonIgnore
@TableLogic
private Date deleteTime;
}
1.1.2、创建BannerItemDO
package io.github.talelin.latticy.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
@TableName("banner_item")
@Getter
@Setter
public class BannerItemDO extends BaseModel {
private String name;
private String img;
private String keyword;
private Integer type;
private Integer bannerId;
}
1.2、创建Mapper
1.2.1创建BannerMapper
package io.github.talelin.latticy.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import io.github.talelin.latticy.model.BannerDO;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface BannerMapper extends BaseMapper<BannerDO> {
List<BannerDO> getAllBanners();
long insertBanner(BannerDO bannerDO);
@Select("SELECT * FROM banner")
List<BannerDO> getAllBanners1();
}
1.2.2创建BannerItemMapper
package io.github.talelin.latticy.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import io.github.talelin.latticy.model.BannerItemDO;
import org.springframework.stereotype.Repository;
@Repository
public interface BannerItemMapper extends BaseMapper<BannerItemDO> {
}
1.3创建BO层,把Banner与BannerItme合拼
package io.github.talelin.latticy.bo;
import io.github.talelin.latticy.model.BannerDO;
import io.github.talelin.latticy.model.BannerItemDO;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.BeanUtils;
import java.util.List;
@Data
@NoArgsConstructor
public class BannerWithItemsBO {
private Integer id;
private String name;
private String title;
private String img;
private String description;
List<BannerItemDO> items;
public BannerWithItemsBO(BannerDO banner, List<BannerItemDO> items) {
BeanUtils.copyProperties(banner, this);
this.setItems(items);
}
}
1.4创建Service
1.4.1创建BannerService接口
package io.github.talelin.latticy.service;
import io.github.talelin.latticy.bo.BannerWithItemsBO;
import io.github.talelin.latticy.dto.BannerDTO;
import io.github.talelin.latticy.model.BannerDO;
import io.github.talelin.latticy.vo.PageResponseVO;
import io.github.talelin.latticy.vo.UpdatedVO;
public interface BannerService {
public PageResponseVO<BannerDO> getBanners(Integer page,Integer count);
public void update(BannerDTO dto, Integer id);
public void delete(Integer id);
public BannerWithItemsBO getWithItems(Integer id);
}
1.4.2创建BannerServiceImpl实现类
package io.github.talelin.latticy.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import io.github.talelin.autoconfigure.exception.NotFoundException;
import io.github.talelin.latticy.bo.BannerWithItemsBO;
import io.github.talelin.latticy.common.mybatis.Page;
import io.github.talelin.latticy.dto.BannerDTO;
import io.github.talelin.latticy.mapper.BannerItemMapper;
import io.github.talelin.latticy.mapper.BannerMapper;
import io.github.talelin.latticy.model.BannerDO;
import io.github.talelin.latticy.model.BannerItemDO;
import io.github.talelin.latticy.service.BannerService;
import io.github.talelin.latticy.vo.PageResponseVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BannerServiceImpl implements BannerService {
@Autowired
private BannerMapper bannerMapper;
@Autowired
private BannerItemMapper bannerItemMapper;
public BannerWithItemsBO getWithItems(Integer id) {
BannerDO banner = bannerMapper.selectById(id);
if (banner == null) {
throw new NotFoundException(20000);
}
/*
* 实例化wrapper,增加条件方法一:
* */
// LambdaQueryWrapper<BannerItemDO> wrapper = new QueryWrapper<BannerItemDO>().lambda();
// wrapper.eq("banner_id", id);
/*
* 实例化wrapper,增加条件方法二:
* */
// LambdaQueryWrapper<BannerItemDO> wrapper = new LambdaQueryWrapper<>();
// wrapper.eq(BannerItemDO::getBannerId, id);
// List<BannerItemDO> bannerItems = bannerItemMapper.selectList(wrapper);
/*
* 条件查询方法三
* */
List<BannerItemDO> bannerItems =
new LambdaQueryChainWrapper<>(bannerItemMapper)
.eq(BannerItemDO::getBannerId, id)
.list();
return new BannerWithItemsBO(banner, bannerItems);
}
public void delete(Integer id) {
BannerDO banner = bannerMapper.selectById(id);
if (banner == null) {
throw new NotFoundException(20000);
}
bannerMapper.deleteById(id);
}
public void update(BannerDTO dto, Integer id){
BannerDO bannerDO = bannerMapper.selectById(id);
if (bannerDO == null) {
throw new NotFoundException(20000);
}
/*
* org.springframework.beans.BeanUtils
* 把dto拷贝到bannerDo中
* */
BeanUtils.copyProperties(dto, bannerDO);
bannerMapper.updateById(bannerDO);
}
public PageResponseVO<BannerDO> getBanners(Integer page,Integer count){
Page<BannerDO> pager = new Page<>(page,count);
IPage<BannerDO> paging = bannerMapper.selectPage(pager, null);
return new PageResponseVO<BannerDO>((int)paging.getTotal(), paging.getRecords(), (int)paging.getCurrent(), (int)paging.getSize());
}
}
QueryWrapper的用法
构建SQL语句中的WHERE条件的方法
- eq:equals,等于
- allEq:all equals,全等于
- ne:not equals,不等于
- gt:greater than ,大于 >
- ge:greater than or equals,大于等于 ≥
- lt:less than,小于 <
- le:less than or equals,小于等于 ≤
- between:相当于SQL中的BETWEEN
- notBetween
- like:模糊匹配。like(“name”,”黄”),相当于SQL的 name like ‘%黄%’
- likeRight:模糊匹配右半边。likeRight(“name”,”黄”),相当于SQL的name like ‘%黄%’
- likeLeft:模糊匹配左半边。likeLeft(“name”,”黄”),相当于SQL的name like ‘%黄’
- notLike :notLike(“name”,”黄”),相当于SQL的name not like ‘%黄%’
- isNull
- isNotNull
- in
- and :SQL连接符AND
- or :SQL连接符OR
- apply :用于拼接SQL,该方法可用于数据库函数,并可以动态传参
// 案例先展示需要完成的SQL语句,后展示Wrapper的写法
// 1. 名字中包含佳,且年龄小于25
// SELECT * FROM user WHERE name like '%佳%' AND age < 25
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like("name", "佳").lt("age", 25);
List<User> users = userMapper.selectList(wrapper);
// 下面展示SQL时,仅展示WHERE条件;展示代码时, 仅展示Wrapper构建部分
// 2. 姓名为黄姓,且年龄大于等于20,小于等于40,且email字段不为空
// name like '黄%' AND age BETWEEN 20 AND 40 AND email is not null
wrapper.likeRight("name","黄").between("age", 20, 40).isNotNull("email");
// 3. 姓名为黄姓,或者年龄大于等于40,按照年龄降序排列,年龄相同则按照id升序排列
// name like '黄%' OR age >= 40 order by age desc, id asc
wrapper.likeRight("name","黄").or().ge("age",40).orderByDesc("age").orderByAsc("id");
// 4.创建日期为2021年3月22日,并且直属上级的名字为李姓
// date_format(create_time,'%Y-%m-%d') = '2021-03-22' AND manager_id IN (SELECT id FROM user WHERE name like '李%')
wrapper.apply("date_format(create_time, '%Y-%m-%d') = {0}", "2021-03-22") // 建议采用{index}这种方式动态传参, 可防止SQL注入
.inSql("manager_id", "SELECT id FROM user WHERE name like '李%'");
// 上面的apply, 也可以直接使用下面这种方式做字符串拼接,但当这个日期是一个外部参数时,这种方式有SQL注入的风险
wrapper.apply("date_format(create_time, '%Y-%m-%d') = '2021-03-22'");
// 5. 名字为王姓,并且(年龄小于40,或者邮箱不为空)
// name like '王%' AND (age < 40 OR email is not null)
wrapper.likeRight("name", "王").and(q -> q.lt("age", 40).or().isNotNull("email"));
// 6. 名字为王姓,或者(年龄小于40并且年龄大于20并且邮箱不为空)
// name like '王%' OR (age < 40 AND age > 20 AND email is not null)
wrapper.likeRight("name", "王").or(
q -> q.lt("age",40)
.gt("age",20)
.isNotNull("email")
);
// 7. (年龄小于40或者邮箱不为空) 并且名字为王姓
// (age < 40 OR email is not null) AND name like '王%'
wrapper.nested(q -> q.lt("age", 40).or().isNotNull("email"))
.likeRight("name", "王");
// 8. 年龄为30,31,34,35
// age IN (30,31,34,35)
wrapper.in("age", Arrays.asList(30,31,34,35));
// 或
wrapper.inSql("age","30,31,34,35");
// 9. 年龄为30,31,34,35, 返回满足条件的第一条记录
// age IN (30,31,34,35) LIMIT 1
wrapper.in("age", Arrays.asList(30,31,34,35)).last("LIMIT 1");
// 10. 只选出id, name 列 (QueryWrapper 特有)
// SELECT id, name FROM user;
wrapper.select("id", "name");
// 11. 选出id, name, age, email, 等同于排除 manager_id 和 create_time
// 当列特别多, 而只需要排除个别列时, 采用上面的方式可能需要写很多个列, 可以采用重载的select方法,指定需要排除的列
wrapper.select(User.class, info -> {
String columnName = info.getColumn();
return !"create_time".equals(columnName) && !"manager_id".equals(columnName);
});
1.5创建Controller
package io.github.talelin.latticy.controller.v1;
import io.github.talelin.core.annotation.GroupRequired;
import io.github.talelin.core.annotation.Logger;
import io.github.talelin.core.annotation.LoginRequired;
import io.github.talelin.core.annotation.PermissionMeta;
import io.github.talelin.latticy.bo.BannerWithItemsBO;
import io.github.talelin.latticy.dto.BannerDTO;
import io.github.talelin.latticy.model.BannerDO;
import io.github.talelin.latticy.service.BannerService;
import io.github.talelin.latticy.vo.DeletedVO;
import io.github.talelin.latticy.vo.PageResponseVO;
import io.github.talelin.latticy.vo.UpdatedVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.Positive;
@RequestMapping("/v1/banner")
@RestController
@Validated
public class BannerController {
@Autowired
private BannerService bannerService;
@GetMapping("/getBannerWithItem/{id}")
public BannerWithItemsBO getWithItems(@PathVariable @Positive Integer id) {
return bannerService.getWithItems(id);
}
@DeleteMapping("/deleteBanner/{id}")
public DeletedVO delete(@PathVariable @Positive Integer id) {
bannerService.delete(id);
return new DeletedVO();
}
@PutMapping("/updateBanner/{id}")
public UpdatedVO update(@RequestBody @Validated BannerDTO dto,
@PathVariable @Positive Integer id) {
bannerService.update(dto, id);
return new UpdatedVO();
}
@GetMapping("/page")
public PageResponseVO<BannerDO> getBanners(
@RequestParam(required = false, defaultValue = "0")
@Min(value = 0) Integer page,
@RequestParam(required = false, defaultValue = "10")
@Min(value = 1) @Max(value = 30) Integer count
){
return bannerService.getBanners(page,count);
}
}
二、一对一/一对多的多条记录查询
2.1.1BannerDO(与上例子一致)
2.1.2创建BannerItemDO (与上例子一致)
2.2.1创建BannerMapper (与上例子一致)
2.2.2创建BannerItemMapper (与上例子一致)
2.3创建BO层,把Banner与BannerItme合拼 (与上例子一致)
2.4创建Service
2.4.1创建Service接口
public List<BannerWithItemsBO> getBannerWithItemsList();
2.4.2创建Service实现类
public List<BannerWithItemsBO> getBannerWithItemsList(){
List<BannerDO> bannerDOList = bannerMapper.selectList(Wrappers.emptyWrapper());
Set<Integer> bannerIds = bannerDOList.stream().map(BannerDO::getId).collect(toSet());
List<BannerItemDO> bannerItemDOList = bannerItemMapper.selectList(Wrappers.lambdaQuery(BannerItemDO.class).in(BannerItemDO::getBannerId, bannerIds));
/*根据bannerid分组*/
Map<Integer, List<BannerItemDO>> hashMap = bannerItemDOList.stream().collect(groupingBy(BannerItemDO::getBannerId));
List<BannerWithItemsBO> bannerWithItemsBOList = bannerDOList.stream().map(e ->
new BannerWithItemsBO(e,hashMap.get(e.getId()))
).collect(toList());
return bannerWithItemsBOList;
}
2.4创建Controller
@GetMapping("/getBannerWithItemsList")
public List<BannerWithItemsBO> getBannerWithItemsList() {
List<BannerWithItemsBO> bannerWithItemsBOList = bannerService.getBannerWithItemsList();
return bannerWithItemsBOList;
}
三、使用JOIN联表
(19条消息) SpringBoot整合Mybatis-Plus—-多表关联查询(使用注解)_懒虫虫~的博客-CSDN博客_springbootmybatisplus多表查询
https://blog.csdn.net/m0_37779570/article/details/81514757
3.1创建BannerDO
package io.github.talelin.latticy.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
import java.util.List;
@Getter
@Setter
@TableName("banner")
public class BannerDO {
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
private String title;
private String description;
private String img;
@Version
private Integer version;
@JsonIgnore
private Date createTime;
@JsonIgnore
private Date updateTime;
/* @TableLogic注解参数
value = "" 默认的原值
delval = "" 删除后的值
@TableLogic(value="原值",delval="改值")
* */
@JsonIgnore
@TableLogic
private Date deleteTime;
//假设我们需要查询一个banner及其下面的item,首先对 Banner 实体类稍作修改,增加 bannerItemList 集合属性
@TableField(exist = false)
private List<BannerItemDO> items;
}
3.2创建BannerItemDO
package io.github.talelin.latticy.model;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.util.Date;
@TableName("banner_item")
@Getter
@Setter
public class BannerItemDO extends BaseModel {
private String name;
private String img;
private String keyword;
private Integer type;
private Integer bannerId;
}
3.3创建BannerMapper
@Repository
public interface BannerMapper extends BaseMapper<BannerDO> {
@Results({
@Result(column = "id", property = "id"),
@Result(column = "id",property = "items",
javaType=List.class,
many =@Many(select="io.github.talelin.latticy.mapper.BannerItemMapper.selectBannerItemByBannerId"))
})
@Select("SELECT * FROM banner where 1=1 ${ew.customSqlSegment}")
List<BannerDO> selecBannertList(@Param(Constants.WRAPPER) Wrapper wrapper);
}
3.4创建BannerItemMapper
package io.github.talelin.latticy.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import io.github.talelin.latticy.model.BannerItemDO;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.io.Serializable;
import java.util.List;
@Repository
public interface BannerItemMapper extends BaseMapper<BannerItemDO> {
@Select({"select b.* from banner_item b",
"where b.banner_id=#{banner_id}"
})
List<BannerItemDO> selectBannerItemByBannerId(@Param("banner_id") Integer banner_id);
}
3.5创建Service
public List<BannerDO> getBannerWithItemsJoinList(){
LambdaQueryWrapper<BannerDO> wrapper = new LambdaQueryWrapper<>();
List<BannerDO> list = bannerMapper.selecBannertList(wrapper);
return list;
}
3.6创建Controller
@GetMapping("/getBannerWithItemsJoinList")
public List<BannerDO> getBannerWithItemsJoinList() {
List<BannerDO> bannerWithItemsBOList = bannerService.getBannerWithItemsJoinList();
return bannerWithItemsBOList;
}
四MyBatis级联删除
通过事务保证一致性。
deleteBatchIds()
五MyBatis数据创建保存
本案例以保存Banner为例子
5.1创建BannerBO
5.2创建BannerMapper
5.3创建BannerDTO
package io.github.talelin.latticy.dto;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
@Getter
@Setter
public class BannerDTO {
@NotBlank
@Length(min = 2, max = 20)
private String name;
@Length(min = 2, max = 30)
private String title;
@Length(min = 2, max = 256)
private String img;
@Length(min = 2, max = 256)
private String description;
}
5.4创建Service
5.4.1创建BannerService接口
package io.github.talelin.latticy.service;
import io.github.talelin.latticy.bo.BannerWithItemsBO;
import io.github.talelin.latticy.dto.BannerDTO;
import io.github.talelin.latticy.model.BannerDO;
import io.github.talelin.latticy.vo.PageResponseVO;
import io.github.talelin.latticy.vo.UpdatedVO;
public interface BannerService {
public PageResponseVO<BannerDO> getBanners(Integer page,Integer count);
public void update(BannerDTO dto, Integer id);
public void delete(Integer id);
public BannerWithItemsBO getWithItems(Integer id);
public void create(BannerDTO bannerDTO);
}
5.4.2创建BannerServiceImpl
package io.github.talelin.latticy.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import io.github.talelin.autoconfigure.exception.NotFoundException;
import io.github.talelin.latticy.bo.BannerWithItemsBO;
import io.github.talelin.latticy.common.mybatis.Page;
import io.github.talelin.latticy.dto.BannerDTO;
import io.github.talelin.latticy.mapper.BannerItemMapper;
import io.github.talelin.latticy.mapper.BannerMapper;
import io.github.talelin.latticy.model.BannerDO;
import io.github.talelin.latticy.model.BannerItemDO;
import io.github.talelin.latticy.service.BannerService;
import io.github.talelin.latticy.vo.PageResponseVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BannerServiceImpl implements BannerService {
@Autowired
private BannerMapper bannerMapper;
@Autowired
private BannerItemMapper bannerItemMapper;
public void create(BannerDTO bannerDTO) {
BannerDO bannerDO = new BannerDO();
BeanUtils.copyProperties(bannerDTO, bannerDO);
bannerMapper.insert(bannerDO);
}
public BannerWithItemsBO getWithItems(Integer id) {
BannerDO banner = bannerMapper.selectById(id);
if (banner == null) {
throw new NotFoundException(20000);
}
/*
* 实例化wrapper,增加条件方法一:
* */
// LambdaQueryWrapper<BannerItemDO> wrapper = new QueryWrapper<BannerItemDO>().lambda();
// wrapper.eq("banner_id", id);
/*
* 实例化wrapper,增加条件方法二:
* */
// LambdaQueryWrapper<BannerItemDO> wrapper = new LambdaQueryWrapper<>();
// wrapper.eq(BannerItemDO::getBannerId, id);
// List<BannerItemDO> bannerItems = bannerItemMapper.selectList(wrapper);
/*
* 条件查询方法三
* */
List<BannerItemDO> bannerItems =
new LambdaQueryChainWrapper<>(bannerItemMapper)
.eq(BannerItemDO::getBannerId, id)
.list();
return new BannerWithItemsBO(banner, bannerItems);
}
public void delete(Integer id) {
BannerDO banner = bannerMapper.selectById(id);
if (banner == null) {
throw new NotFoundException(20000);
}
bannerMapper.deleteById(id);
}
public void update(BannerDTO dto, Integer id){
BannerDO bannerDO = bannerMapper.selectById(id);
if (bannerDO == null) {
throw new NotFoundException(20000);
}
/*
* org.springframework.beans.BeanUtils
* 把dto拷贝到bannerDo中
* */
BeanUtils.copyProperties(dto, bannerDO);
bannerMapper.updateById(bannerDO);
}
public PageResponseVO<BannerDO> getBanners(Integer page,Integer count){
Page<BannerDO> pager = new Page<>(page,count);
IPage<BannerDO> paging = bannerMapper.selectPage(pager, null);
return new PageResponseVO<BannerDO>((int)paging.getTotal(), paging.getRecords(), (int)paging.getCurrent(), (int)paging.getSize());
}
}