Mybatis-plus联表查询 -- mybatis-plus-join

以t_order、t_user、t_product三表联合查询为例,其中t_order表为主表。

0.数据源配置

在springboot项目中,像往常一样正常配置数据源。

1.引入依赖

首先在项目中引入引入依赖坐标,因为mpj中依赖较高版本mybatis-plus中的一些api,所以项目建议直接使用高版本。

<dependency>
    <groupId>com.github.yulichang</groupId>
    <artifactId>mybatis-plus-join</artifactId>
    <version>1.2.4</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>https://www.zhihu.com/search?q=mybatis-plus-boot-starter&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22answer%22%2C%22sourceId%22%3A2591368778%7D</artifactId>
    <version>3.5.1</version>
</dependency>

2.加入分页拦截器

mpj中也能很好的支持列表查询中的分页功能,首先我们要在项目中加入分页拦截器

java 复制代码
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
    return interceptor;
}

2.修改Mapper

把原Mapper层接口都是继承的BaseMapper,改为继承MPJBaseMapper接口。

java 复制代码
@Mapper
public interface OrderMapper extends MPJBaseMapper<Order> {
}

对其余几个参与联表查询的表的Mapper接口也进行相同的改造。

3.修改Service

service也可以选择继承MPJBaseServiceserviceImpl选择继承MPJBaseServiceImpl,这两者为非必须继承。

4.注入Mapper

Mapper接口改造完成后,我们把它注入到各自Service中,以t_order作为主表的话,那么只注入这一个对应的OrderMapper就可以。

java 复制代码
@Service
@AllArgsConstructor
public class OrderServiceImpl implements OrderService {
    private final OrderMapper orderMapper;
}

5.使用MPJLambdaWrapper联表查询

java 复制代码
public void page() {
    IPage<OrderDto> orderPage = orderMapper.selectJoinPage(
      new Page<OrderDto>(2,10),
      OrderDto.class,
      new MPJLambdaWrapper<Order>()
        .selectAll(Order.class)
        .select(Product::getUnitPrice)
        .selectAs(User::getName, OrderDto::getUserName)
        .selectAs(Product::getName, OrderDto::getProductName)
        .leftJoin(User.class, User::getId, Order::getUserId)
        .leftJoin(Product.class, Product::getId, Order::getProductId)
        .orderByAsc(Order::getId));

    orderPage.getRecords().forEach(System.out::println);
}

如果不需要分页,则:

java 复制代码
public void getOrder() {
    List<OrderDto> list = orderMapper.selectJoinList(OrderDto.class,
     new MPJLambdaWrapper<Order>()
      .selectAll(Order.class)
      .select(Product::getUnitPrice)
      .selectAs(User::getName,OrderDto::getUserName)
      .selectAs(Product::getName,OrderDto::getProductName)
      .leftJoin(User.class, User::getId, Order::getUserId)
      .leftJoin(Product.class, Product::getId, Order::getProductId)
      .eq(Order::getStatus,3));

    list.forEach(System.out::println);
}

参数OrderDto.class代表接收返回查询结果的类,作用和我们之前在xml中写的resultType类似。

这个类可以直接继承实体,再添加上需要在关联查询中返回的列即可:

java 复制代码
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class OrderDto extends Order {
    String userName;
    String productName;
    Double unitPrice;
}

接下来的MPJLambdaWrapper就是构建查询条件的核心了,看一下我们在上面用到的几个方法:

  • selectAll():查询指定实体类的全部字段
  • select():查询指定的字段,支持可变长参数同时查询多个字段,但是在同一个select中只能查询相同表的字段,所以如果查询多张表的字段需要分开写
  • selectAs():字段别名查询,用于数据库字段与接收结果的dto中属性名称不一致时转换
  • leftJoin()左连接,其中第一个参数是参与联表的表对应的实体类,第二个参数是这张表联表的ON字段,第三个参数是参与联表的ON的另一个实体类属性

除此之外,还可以正常调用mybatis-plus中的各种原生方法,文档中还提到,默认主表别名是t,其他的表别名以先后调用的顺序使用t1t2t3以此类推。

另:也可以使用MPJQueryWrapper

mybatis-plus非常类似,除了MPJLamdaWrapper外还提供了普通MPJQueryWrapper,写法上比MPJLambdaWrapper麻烦。改造上面的代码:

public void getOrderSimple() {
    List<OrderDto> list = orderMapper.selectJoinList(OrderDto.class,
     new MPJQueryWrapper<Order>()
      .selectAll(Order.class)
      .select("t2.unit_price","t2.name as product_name")
      .select("t1.name as user_name")
      .leftJoin("t_user t1 on t1.id = t.user_id")
      .leftJoin("t_product t2 on t2.id = https://www.zhihu.com/search?q=t.product_id&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22answer%22%2C%22sourceId%22%3A2591368778%7D")
      .eq("t.status", "3")
    );

    list.forEach(System.out::println);
}

运行结果与之前完全相同,需要注意的是,这样写时在引用表名时不要使用数据库中的原表名,主表默认使用t,其他表使用join语句中我们为它起的别名,如果使用原表名在运行中会出现报错。

并且,在MPJQueryWrapper中,可以更灵活的支持子查询操作,如果业务比较复杂,那么使用这种方式也是不错的选择。

参考:mybatis-plus的queryWrapper能不能实现表关联? - 知乎

QueryWrapper

类似的,如果不适用mybatis-plus-join来联合查询,也可以直接使用mybatis-plus的QueryWrapper 来写复杂点的SQL查询,用法如MPJQueryWrapper。

例如:

分页拦截器依然需要:

java 复制代码
 @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

改造Mapper:

java 复制代码
@Repository
public interface BlogMapper extends BaseMapper<Blog> {
    /**
     * 静态查询
     */
    @Select("SELECT t_user.user_name " +
            " FROM t_blog, t_user " +
            " WHERE t_blog.id = #{id} " +
            "     AND t_blog.user_id = t_user.id")
    String findUserNameByBlogId(@Param("id") Long id);
     * 动态查询
    @Select("SELECT * " +
            " ${ew.customSqlSegment} ")
    IPage<BlogVO> findBlog(IPage<BlogVO> page, @Param("ew") Wrapper wrapper);
}

改造联合查询:

java 复制代码
public IPage<BlogVO> dynamicQuery(Page<BlogVO> page, String nickName, String title) {
        QueryWrapper<BlogVO> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(StringUtils.hasText(nickName), "t_user.nick_name", nickName);
        queryWrapper.like(StringUtils.hasText(title), "t_blog.title", title);
        queryWrapper.eq("t_blog.deleted_flag", 0);
        queryWrapper.eq("t_user.deleted_flag", 0);
        queryWrapper.apply("t_blog.user_id = t_user.id");
        return blogMapper.findBlog(page, queryWrapper);
}

查看:MyBatis-Plus怎么实现多表联查 - 开发技术 - 亿速云

最后保底的办法

不使用Mybatis-plus,和之前一样直接在xml中写SQL。

相关推荐
aloha_7896 小时前
从零记录搭建一个干净的mybatis环境
java·笔记·spring·spring cloud·maven·mybatis·springboot
毕业设计制作和分享7 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
paopaokaka_luck10 小时前
基于Spring Boot+Vue的助农销售平台(协同过滤算法、限流算法、支付宝沙盒支付、实时聊天、图形化分析)
java·spring boot·小程序·毕业设计·mybatis·1024程序员节
cooldream200911 小时前
Spring Boot中集成MyBatis操作数据库详细教程
java·数据库·spring boot·mybatis
不像程序员的程序媛12 小时前
mybatisgenerator生成mapper时报错
maven·mybatis
小布布的不14 小时前
MyBatis 返回 Map 或 List<Map>时,时间类型数据,默认为LocalDateTime,响应给前端默认含有‘T‘字符
前端·mybatis·springboot
背水16 小时前
Mybatis基于注解的关系查询
mybatis
free_girl_fang17 小时前
高效作业之Mybatis缓存
java·ide·缓存·mybatis
十二同学啊20 小时前
Mybatis拦截器中获取@RequestBody表单的值修改查询SQL
数据库·sql·mybatis
毕业设计制作和分享21 小时前
ssm好例文共享平台的设计与实现+jsp
java·开发语言·vue.js·spring boot·毕业设计·mybatis