MyBatis-Plus | 最優雅最簡潔地完成數據庫操作

原文鏈接:https://www.jianshu.com/p/0ecd429427b6

引言

兩點:

一,使用MyBatis-Plus最新版(3.0.1)完成相關操作

二,好久沒寫MyBatis操作數據庫的博文了,有沒有想我啊,哈哈,認真看,認真聽,認真學。

測試效果:

使用swagger2顯示API接口

swagge2 接口以及model信息

分頁接口測試.png

下面聽我細細道來,MyBatis-Plus的優雅、簡潔與強大。

代碼生成器

代碼生成器,又被叫做逆向工程,MyBatis官方爲了推廣,自己也寫了一個,我之前也使用這個,功能也是非常強大,強大以爲支持自定義配置,那麼問題來了,我該怎麼配置才合理呢,所以,有人把所有的配置項都弄成中文的,還有人開發了生成插件,這些在我以往的博文中都看看到。MyBatis-Plus的代碼生成器到底怎麼樣,這我就不評判了,我就這樣說,用用看吧。

在MyBatis-Plus的官網文檔中,有將代碼生成器的問題,有配置詳解,也有項目示例代碼,複製來就可用。

我這次是用MP 3.0.1,也就是最新版,官方還沒有更新呢,所以,我去找了很久的源碼,纔將這個完成,勉強適合自己的了。這個在 CodeGenerator Module中,可以下下下來,導入到IDE中,看一下,修改配置就能運行。有問題,也可以與我討論。

功能列表:

  • [✔] 自動生成model類

  • [✔] 自動生成dao接口

  • [✔] 自動生成xml文件

  • [✔] 自動生成service接口

  • [✔] 自動生成service實現類

  • [✔] model支持Builder模式

  • [✔] 支持swagger2

  • [✔] 支持生成數據庫字段常量

  • [✔] 支持生成Kotlin代碼

  • [] ......

項目初始化

第一步:pom.xml引入MyBatis-Plus依賴,注意,不需要再引入MyBatis的包,因爲我這裏使用Spring Boot搭建的工程,所有因爲方式見下:

<dependencies>
    ...
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.1</version>
    </dependency>
    ...
</dependencies>

第二步:將生成的代碼,拷貝到相應的包下

代碼目錄結構

第三步:在配置文件中進行相應的配置

具體配置可參考官網,這裏需要注意這樣幾個地方:

mybatis-plus:
  # xml
  mapper-locations: classpath:mapper/*Mapper.xml
  # 實體掃描,多個package用逗號或者分號分隔
  type-aliases-package: com.fengwenyi.mp3demo.model
  configuration:
    # 這個配置會將執行的sql打印出來,在開發或測試的時候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

日誌:分頁查詢

第四步:在啓動類上添加下面的註解

@EnableTransactionManagement
@MapperScan("com.fengwenyi.mp3demo.dao")

增刪改

Service

我們一起去看源碼 com.baomidou.mybatisplus.extension.service.IService<T>

增加:

    /**
     * <p>
     * 插入一條記錄(選擇字段,策略插入)
     * </p>
     *
     * @param entity 實體對象
     */
    boolean save(T entity);

修改:

    /**
     * <p>
     * 根據 ID 選擇修改
     * </p>
     *
     * @param entity 實體對象
     */
    boolean updateById(T entity);

    /**
     * <p>
     * 根據 whereEntity 條件,更新記錄
     * </p>
     *
     * @param entity        實體對象
     * @param updateWrapper 實體對象封裝操作類 
     * {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
     */
    boolean update(T entity, Wrapper<T> updateWrapper);

刪除:

    /**
     * <p>
     * 根據 ID 刪除
     * </p>
     *
     * @param id 主鍵ID
     */
    boolean removeById(Serializable id);

    /**
     * <p>
     * 根據 entity 條件,刪除記錄
     * </p>
     *
     * @param queryWrapper 實體包裝類 
     * {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    boolean remove(Wrapper<T> queryWrapper);

Mapper

com.baomidou.mybatisplus.core.mapper.BaseMapper<T>

增加:

    /**
     * <p>
     * 插入一條記錄
     * </p>
     *
     * @param entity 實體對象
     */
    int insert(T entity);

修改:

    /**
     * <p>
     * 根據 whereEntity 條件,更新記錄
     * </p>
     *
     * @param entity        實體對象 (set 條件值,不能爲 null)
     * @param updateWrapper 實體對象封裝操作類(可以爲 null,裏面的 entity 用於生成 where 語句)
     */
    int update(@Param(Constants.ENTITY) T entity, 
               @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);

    /**
     * <p>
     * 根據 ID 修改
     * </p>
     *
     * @param entity 實體對象
     */
    int updateById(@Param(Constants.ENTITY) T entity);

刪除:

    /**
     * <p>
     * 根據 entity 條件,刪除記錄
     * </p>
     *
     * @param queryWrapper 實體對象封裝操作類(可以爲 null)
     */
    int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

    /**
     * <p>
     * 根據 ID 刪除
     * </p>
     *
     * @param id 主鍵ID
     */
    int deleteById(Serializable id);

以上相當於是常用API了,我們去看看,他是怎麼實現的。毫無疑問,Mapper是底層,Service調用Mapper去執行sql,完成相關操作,所以,你完全可以直接調用Mapper完成相關操作,就跟使用MyBatis一樣。下面我們去看看,他幫我們寫的Service是什麼樣子,這裏只看一個修改操作吧。

接口:

    /**
     * <p>
     * 根據 whereEntity 條件,更新記錄
     * </p>
     *
     * @param entity        實體對象
     * @param updateWrapper 實體對象封裝操作類
     * {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
     */
    boolean update(T entity, Wrapper<T> updateWrapper);

實現:

    @Override
    public boolean update(T entity, Wrapper<T> updateWrapper) {
        return ServiceImpl.retBool(baseMapper.update(entity, updateWrapper));
    }

    /**
     * <p>
     * 判斷數據庫操作是否成功
     * </p>
     * <p>
     * 注意!! 該方法爲 Integer 判斷,不可傳入 int 基本類型
     * </p>
     *
     * @param result 數據庫操作返回影響條數
     * @return boolean
     */
    protected static boolean retBool(Integer result) {
        return SqlHelper.retBool(result);
    }

    /**
     * <p>
     * 判斷數據庫操作是否成功
     * </p>
     *
     * @param result 數據庫操作返回影響條數
     * @return boolean
     */
    public static boolean retBool(Integer result) {
        return null != result && result >= 1;
    }

哈哈,是不是我們自己也會這樣寫啊!

查詢

接下來,我們一起討論下查詢吧。

MP 3.x,查詢接口發生了很大的變化,反正我是不喜歡的,你就弄一個什麼開頭啊,到時候,我一點就知道有哪些方法了,他這裏有 list*get*,反正就是一個字——沒必要。

先看下接口說明:

    /**
     * <p>
     * 查詢列表
     * </p>
     *
     * @param queryWrapper 實體對象封裝操作類 
     * {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    List<T> list(Wrapper<T> queryWrapper);

      /**
     * <p>
     * 根據 ID 查詢
     * </p>
     *
     * @param id 主鍵ID
     */
    T getById(Serializable id);

    /**
     * <p>
     * 根據 Wrapper,查詢一條記錄
     * </p>
     *
     * @param queryWrapper 實體對象封裝操作類
     * {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    T getOne(Wrapper<T> queryWrapper);

嗯,差不多了吧,這樣需要注意這樣一個方法:

    /**
     * <p>
     * 從list中取第一條數據返回對應List中泛型的單個結果
     * </p>
     *
     * @param list
     * @param <E>
     * @return
     */
    public static <E> E getObject(List<E> list) {
        if (CollectionUtils.isNotEmpty(list)) {
            int size = list.size();
            if (size > 1) {
                SqlHelper.logger.warn(
String.format("Warn: execute Method There are  %s results.", size));
            }
            return list.get(0);
        }
        return null;
    }

下面說下分頁的問題

根據官網的說法,需要藉助插件,這我們是可以理解。

在Spring Boot啓動類裏面添加:

    /**
     * 分頁插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

這樣就可以使用他提供的分頁接口了:

    /**
     * <p>
     * 翻頁查詢
     * </p>
     *
     * @param page         翻頁對象
     * @param queryWrapper 實體對象封裝操作類
     * {@link com.baomidou.mybatisplus.core.conditions.query.QueryWrapper}
     */
    IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);

我們去看一下:

    @Override
    public IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper) {
        queryWrapper = (Wrapper<T>) SqlHelper.fillWrapper(page, queryWrapper);
        return baseMapper.selectPage(page, queryWrapper);
    }

    /**
     * <p>
     * 填充Wrapper
     * </p>
     *
     * @param page    分頁對象
     * @param wrapper SQL包裝對象
     */
    @SuppressWarnings("unchecked")
    public static Wrapper<?> fillWrapper(IPage<?> page, Wrapper<?> wrapper) {
        if (null == page) {
            return wrapper;
        }
        if (ArrayUtils.isEmpty(page.ascs())
            && ArrayUtils.isEmpty(page.descs())
            && ObjectUtils.isEmpty(page.condition())) {
            return wrapper;
        }
        QueryWrapper qw;
        if (null == wrapper) {
            qw = new QueryWrapper<>();
        } else {
            qw = (QueryWrapper) wrapper;
        }
        // 排序
        if (ArrayUtils.isNotEmpty(page.ascs())) {
            qw.orderByAsc(page.ascs());
        }
        if (ArrayUtils.isNotEmpty(page.descs())) {
            qw.orderByDesc(page.descs());
        }
        // MAP 參數查詢
        if (ObjectUtils.isNotEmpty(page.condition())) {
            qw.allEq(page.condition());
        }
        return qw;
    }

    /**
     * <p>
     * 根據 entity 條件,查詢全部記錄(並翻頁)
     * </p>
     *
     * @param page         分頁查詢條件(可以爲 RowBounds.DEFAULT)
     * @param queryWrapper 實體對象封裝操作類(可以爲 null)
     */
    IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

分頁的代碼大抵就是這樣,我之前也自己寫過,思路還是相當來說比較簡單,關鍵是看你的查詢添加如何封裝,分頁類如何構造。

這裏有一點說明:

分頁從 1 開始 !!!

枚舉類

1、實現 接口

/**
 * <p>
 * 自定義枚舉接口
 * </p>
 *
 * @author hubin
 * @since 2017-10-11
 */
public interface IEnum<T extends Serializable> {

    /**
     * 枚舉數據庫存儲值
     */
    T getValue();

}

2、實現注意

    @Override
    public Integer getValue() {
        return this.value;
    }

    @JsonValue
    public String getDesc() {
        return desc;
    }

這是Jackson的寫法,我沒用FastJson,所以用的夥伴,去官網看一下:FastJson看官網

3:被忘了在配置文件中添加掃描:

mybatis-plus:
  # 掃描枚舉類 # 支持統配符 * 或者 ; 分割
  type-enums-package: com.fengwenyi.mp3demo.enums

差不多了吧,好像

邏輯刪除

1、代碼生成器中配置:

new StrategyConfig().setLogicDeleteFieldName("is_delete") // 邏輯刪除屬性名稱

或者,你可以手寫,參考:

    @ApiModelProperty(value = "是否邏輯刪除(true:刪除;false:正常(默認))")
    @TableLogic
    private Boolean isDelete;

2、自定義數據庫的值:

mybatis-plus:
  global-config:
    db-config:
      #邏輯刪除配置
      logic-delete-value: 1
      logic-not-delete-value: 0

MyBatis-Plus-Example

MyBatis-Plus的代碼都會上傳到github上

https://github.com/fengwenyi/MyBatis-Plus-Example

參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章