多表聯合查詢 - 基於注解SQL


作者:湯圓

個人博客:javalover.cc

前言

背景:Spring Boot + MybatisPlus

用MybatisPlus就是為了不寫SQL,用起來方便;

但是如果需要多表聯合查詢,還是需要手寫SQL(不過GitHub上也是有一些開源的庫,可以不寫SQL)

本節介紹的還是通用的寫法,基於注解SQL實現的多表聯合查詢

簡介

大概流程就是

  1. 先把要聯合查詢的參數封裝到一個類里進行返回 - 結果類
  2. 再在mapper中注入SQL查詢語句 - @Select
  3. 最后在service中拼接查詢條件 - QueryWrapper構造器(這里沒用Lambda構造器,因為它不支持編寫自定義的字段名)

正文

我們就按照上面的流程來演示:

先貼一下這里我們要執行的SQL查詢語句:這里只貼了我們手寫的部分,還有一部分是程序在后面自動追加的(比如條件、分頁),這里先不寫

select device.*, car.car_number from gps_device as device left join gps_car as car on device.car_id = car.car_id

1. 定義實體結果類

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DeviceResult extends Device implements Serializable {

    /**
     * 車牌號:只有這個屬性是聯合Car查詢的,其他屬性都是Device自帶的
     */
    private String carNumber;

    /**
     * 設備id
     */
    private Long deviceId;

    /**
     * 車輛id
     */
    private Long carId;

    /**
     * 設備類型:0-無線,1-有線
     */
    private Integer deviceType;

    /**
     * 設備編號
     */
    private String deviceNumber;

    /**
     * SIM卡號
     */
    private String simNumber;

}

可以看到,這里我們將聯合查詢的carNumber封裝了進去,這樣返回時,就可以將設備信息和車牌號一並返回(多表聯合查詢的目的就是這個,聯合多個表的數據進行返回)

2. mapper中注入SQL語句

這里有多種方式:

  • 基於注解
  • 基於xml

這里我們用的是基於注解(因為Spring Boot中xml的使用還是比較少的)

DeviceMapper.java

public interface DeviceMapper extends BaseMapper<Device> {
    /**
     * 聯合查詢 left join car
     */
    @Select("select device.*, car.car_number from gps_device as device left join gps_car as car on device.car_id = car.car_id ${ew.customSqlSegment}")
    Page<DeviceResult> joinCarPage(Page<?> page, @Param(Constants.WRAPPER) Wrapper<Device> wrapper);
}

代碼說明:

  • @Select注解:注入SQL語句

  • @Param(Constants.WRAPPER) Wrapper<Device> wrapper: 這個注解有點類似@RequestParam,用來代替SQL語句中的ew變量(如果把形參wrapper改為ew,就不需要加@Param注解);

    這里的構造器wrapper中的自定義SQL會自動追加到@Select語句的后面,最后的service中會有拼接結果SQL

  • BaseMapper:Mybatis-Plus的基類Mapper,封裝了各種常用的數據庫操作(增刪改查分頁等),有了它,一些基本的操作(增刪改查等)我們就不用自己去寫SQL

  • Page:Mybatis-Plus中的分頁對象,將聯合查詢的數據進行分頁;這里的分頁相關的SQL會自動追加到wrapper包裝器的后面(同上面的wrapper)

最后拼接的SQL為:

select device.*, car.car_number from gps_device as device left join gps_car as car on device.car_id = car.car_id LIMIT ?,?

其中limit ?, ?就是Page自動追加的SQL,wrapper追加的SQL在下面的service中定義

3. Service中調用mapper

此時在Service中就不能再使用Lambda表達式了,因為這里需要自定義字段名

核心代碼如下:

QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(ObjectUtil.isNotEmpty(deviceParam.getDeviceType()), "device.device_type", deviceParam.getDeviceType());
queryWrapper.like(ObjectUtil.isNotEmpty(deviceParam.getCarNumber()), "car.car_number", deviceParam.getCarNumber());

最后拼接的SQL為:(這里假設deviceType和carNumber都有傳進來)

select device.*, car.car_number from gps_device as device left join gps_car as car on device.car_id = car.car_id where (device.device_number = ? and car.car_number = ?) LIMIT ?,?

總結

基於注解的多表聯合查詢,分三步:

  1. 定義實體結果類:封裝需要多表聯合查詢的數據
  2. 在mapper中注入SQL語句
  3. 在service中調用mapper,拼接where條件

后記

其實這種寫法還是比較繁瑣的,但好在用的不多;如果用的多,建議去找一些開源的庫來整合


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM