chuyx筆記-MybatisPlus

衣者Serendipity發表於2020-11-16

Mybatis-plus

介紹

MyBatis-Plus(簡稱 MP)是一個 MyBatis 的增強工具,在 MyBatis 的基礎上只做增強不做改變,為簡化開發、提高效率而生。

特性

  • 無侵入:只做增強不做改變,引入它不會對現有工程產生影響,如絲般順滑

  • 損耗小:啟動即會自動注入基本 CURD,效能基本無損耗,直接物件導向操作

  • 強大的 CRUD 操作:內建通用 Mapper、通用 Service,僅僅通過少量配置即可實現單表大部分 CRUD 操作,更有強大的條件構造器,滿足各類使用需求

  • 支援 Lambda 形式呼叫:通過 Lambda 表示式,方便的編寫各類查詢條件,無需再擔心欄位寫錯

  • 支援主鍵自動生成:支援多達 4 種主鍵策略(內含分散式唯一 ID 生成器 - Sequence),可自由配置,完美解決主鍵問題

  • 支援 ActiveRecord 模式:支援 ActiveRecord 形式呼叫,實體類只需繼承 Model 類即可進行強大的 CRUD 操作

  • 支援自定義全域性通用操作:支援全域性通用方法注入( Write once, use anywhere )

  • 內建程式碼生成器:採用程式碼或者 Maven 外掛可快速生成 Mapper 、 Model 、 Service 、 Controller 層程式碼,支援模板引擎,更有超多自定義配置等您來使用

  • 內建分頁外掛:基於 MyBatis 物理分頁,開發者無需關心具體操作,配置好外掛之後,寫分頁等同於普通 List 查詢

  • 分頁外掛支援多種資料庫:支援 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多種資料庫

  • 內建效能分析外掛:可輸出 Sql 語句以及其執行時間,建議開發測試時啟用該功能,能快速揪出慢查詢

  • 內建全域性攔截外掛:提供全表 delete 、 update 操作智慧分析阻斷,也可自定義攔截規則,預防誤操作

    框架結構

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-sS0NdPZJ-1605533209752)(C:\Users\cyx\AppData\Roaming\Typora\typora-user-images\image-20200701175722021.png)]

依賴

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.1.RELEASE</version>
    <relativePath/>
</parent>

yml中的資料庫配置

# DataSource Config
spring:
  datasource:
    driver-class-name: org.h2.Driver
    schema: classpath:db/schema-h2.sql
    data: classpath:db/data-h2.sql
    url: jdbc:h2:mem:test
    username: root
    password: test

或者propertices

#連線資料的配置
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatisplus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

入門案列注意事項:資料庫的欄位名必須和po類的屬性一一對應,不能有絲毫差錯。否則報低階sql語句錯誤,打臉!!!

入門所需類:po與資料庫欄位一一對應的實體類,繼承了BaseMapper的Mapper介面,並且需要加入@Repository註解配置bean。

CRUD

插入:

Mapper.insert(po類); //返回一個int型別的值,代表插入了多少行(影響了幾行)

當po類並沒有設定id時,mp會自動設定id,採用的是雪花演算法

常用註解:

註解名作用
@TableName(“XXX”)指定該類對應的表為XXX,(註解在po類上)
@TableId指定該屬性為Id(這樣才會自動採用雪花演算法填充Id)
註解在屬性上
@TableFiled(“XXX”)指定該屬性為資料庫列名為XXX的對應屬性
註解在屬性上

排除非表欄位的三種方式:

關鍵字:transient:表明這個屬性是非表欄位,不參與與資料的對映關係,不參與序列化放在型別前

標識為靜態變數:全類一份,不參與和資料的對映

@TableField(exist = false):不參與和資料庫的對映,註解在屬性上

普通查詢

T Mapper.selectById(Serializable Id):有主鍵查記錄

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

List Mapper.selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList)

/**
     * <p>
     * 查詢(根據ID 批量查詢)
     * </p>
     *
     * @param idList 主鍵ID列表(不能為 null 以及 empty)
     */
    List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

List Mapper.selectByMap(Map<Object, Object> columnMap):map的key對應資料庫的欄位,value對應資料庫對應的值

精準查詢。如:

Map<String,Object> map = new HashMap<>();
map.put("id",1);
map.put("name","張山");
List<User> users = userMapper.selectBymap(map);

這個就相當於sql:select * from user where id = 1 and name = '張三';
/**
     * <p>
     * 查詢(根據 columnMap 條件)
     * </p>
     *
     * @param columnMap 表欄位 map 物件
     */
    List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

條件構造器的查詢

條件構造器:QueryWrapper 繼承了 AbstracWrapper
兩種方式建立:QueryWrapper w1 = new QueryWrapper<>();

​ QueryWrapper w2 = Warppers..query(); 版本3.1.0之後採用

       //名字中包含了雨並且年齡小於40
    @Test
    public void test20(){
        QueryWrapper<Emp> userQueryWrapper = new QueryWrapper<>();
       // QueryWrapper<User> query = Wrappers.<User>query();
        userQueryWrapper.like("name", "雨").lt("age", 40);
        List<Emp> emps = empMapper.selectList(userQueryWrapper);
        emps.forEach(System.out::println);
    }

    //名字中包含了雨並且年齡大於等於20小於等於40並且email不為空
    @Test
    public void test21(){
        QueryWrapper<Emp> userQueryWrapper = new QueryWrapper<>();
        // QueryWrapper<User> query = Wrappers.<User>query();
        userQueryWrapper.like("name", "雨").between("age",20,40)
                .isNotNull("email");
        List<Emp> emps = empMapper.selectList(userQueryWrapper);
        emps.forEach(System.out::println);
    }

    //名字中為王姓或者年齡大於等於25,按照年齡降序排序,年齡相同按照id排序
    @Test
    public void test22(){
        QueryWrapper<Emp> userQueryWrapper = new QueryWrapper<>();
        // QueryWrapper<User> query = Wrappers.<User>query();
        userQueryWrapper.likeRight("name","王").or().ge("age",25)
        .orderByDesc("age").orderByAsc("id");
        List<Emp> emps = empMapper.selectList(userQueryWrapper);
        emps.forEach(System.out::println);
    }

    //建立日期為2019-2-14並且直屬上級名字為王姓
    @Test
    public void test23(){
        QueryWrapper<Emp> query = Wrappers.<Emp>query();
        query.apply("date_format(create_time,'%Y-%m-%d') = {0}","2019-01-11")
                .inSql("manger_id","select id from emp where name like '王%'");
        List<Emp> emps = empMapper.selectList(query);
        emps.forEach(System.out::println);
    }

    //名字為王姓並且(年齡小於40或郵箱不為空)
    @Test
    public void test24(){
        QueryWrapper<Emp> query = Wrappers.<Emp>query();
        query.likeRight("name", "王")
                .and((empp) -> {
                    empp.lt("age", 40)
                            .or()
                            .isNotNull("email");
                    return empp;
                });
        List<Emp> emps = empMapper.selectList(query);
        emps.forEach(System.out::println);
    }

    //名字為王姓或者  (年齡小於40並且年齡大於20並且郵箱不為空)
    @Test
    public void test25(){
        QueryWrapper<Emp> query = Wrappers.<Emp>query();
        query.likeRight("name", "王")
                .or(qw -> qw.lt("age", 40)
                        .and(qw2 -> qw2.gt("age", 20)
                        .and(qw3 -> qw3.isNotNull("email"))));
        List<Emp> emps = empMapper.selectList(query);
        emps.forEach(System.out::println);
    }

    //年齡為30,31,34,34的
    @Test
    public void test26(){
        QueryWrapper<Emp> query = Wrappers.<Emp>query();
        query.in("age", Arrays.asList(30,31,34,35));
        List<Emp> emps = empMapper.selectList(query);
        emps.forEach(System.out::println);
    }

    //(年齡小於40或者郵箱不為空)  並且為王姓
    @Test
    public void test27(){
        QueryWrapper<Emp> query = Wrappers.<Emp>query();
        query.nested(qw -> qw.lt("age", 40)
                .or()
                .isNotNull("email"))
                .likeRight("name", "王");
        List<Emp> emps = empMapper.selectList(query);
        emps.forEach(System.out::println);
    }

補充不常用條件構造器:

一:nested(fun) : 放在前面的宣告式函式,裡面是函式型介面

二:last(String sql):直接拼接sql語句,一般放最後,只能用一次,多次使用只會拼接最後的last,慎用,有sql注入的風險

select中欄位不全出現的欄位

一、在queryWrapper中新增select(“key”…):

如:queryWrapper.select(“id”, “name”)… //只查詢id,name兩個欄位

二、在queryWrapper中新增select(po.class, Predicate);

如:

queryWrapper.select(Emp.class, info -> !info.getColumn().equals("update_time")&&
     !info.getColumn().equals("manger_id"));
     斷言式介面,排除update_time, manger_id兩個欄位,其他欄位能查出。

condition的作用

大多方法其實都可以多一個condition的引數,它為一個boolean值,為false時該條件不加入sql,為true時該條件加入sql,用於前端輸入沒輸入都可查詢。比如:場景為前端有個查詢頁面,有兩個輸入框,輸入框可有值可沒值,有值是設condition為true,加入條件,反之則反

建立條件構造器傳入實體物件

會將實體物件中的值獲取出來作為條件進行等值查詢

**當不想使用等值時:**在欄位上加@TableName(condition = SqlCondition.XXX),裡面有很多常量,如下

public static final String EQUAL = "%s=#{%s}";
public static final String NOT_EQUAL = "%s&lt;&gt;#{%s}";
public static final String LIKE = "%s LIKE CONCAT('%%',#{%s},'%%')";
public static final String LIKE_LEFT = "%s LIKE CONCAT('%%',#{%s})";
public static final String LIKE_RIGHT = "%s LIKE CONCAT(#{%s},'%%')";
也可以仿照%s LIKE CONCAT(#{%s},'%%'這種新式自定義:第一個%s可以理解為列名,CONCAT(#{%s},'%%'理解為傳進去的

條件構造器中的allEq的使用

  • allEq(Map<R, V> params) : 裡面的key對應欄位,value對應值
  • allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean flag) : flag用來判斷忽略不忽略null
  • allEq(BiPredicate<R, V> filter, Map<R, V> params) :

BiPredicate<R, V> 是一個函式式介面,傳入兩個引數,傳出一個boolean,當boolean值為false的時候,該欄位將被過濾

以上都有加condition的過載函式

其他以條件構造器為引數的查詢方法

 /**
     * 根據 Wrapper 條件,查詢全部記錄
     *
     * @param queryWrapper 實體物件封裝操作類(可以為 null)
     */
    List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
     * 根據 Wrapper 條件,查詢全部記錄
     * <p>注意: 只返回第一個欄位的值</p>
     *
     * @param queryWrapper 實體物件封裝操作類(可以為 null)
     */
    List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
     * 根據 Wrapper 條件,查詢總記錄數
     *
     * @param queryWrapper 實體物件封裝操作類(可以為 null)
     */
    Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
     * 根據 Wrapper 條件,查詢全部記錄
     * <p>注意: 只返回第一個欄位的值</p>
     *
     * @param queryWrapper 實體物件封裝操作類(可以為 null)
     */
    List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

==注意:==當返回兩條記錄時,會報錯

lambda條件構造器:提供了仿誤寫功能

構建lambda條件構造器的三種方式

@Test
    public void queryWrapperLambda(){
        LambdaQueryWrapper<Emp> lambda = new QueryWrapper<Emp>().lambda();
        LambdaQueryWrapper<Emp> empLambdaQueryWrapper = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<Emp> empLambdaQueryWrapper1 = Wrappers.<Emp>lambdaQuery();

    }

使用示例:

@Test
    public void queryWrapperLambda(){
        LambdaQueryWrapper<Emp> empLambdaQueryWrapper1 = Wrappers.<Emp>lambdaQuery();
        empLambdaQueryWrapper1.like(Emp::getName,"雨");
        List<Emp> emps = empMapper.selectList(empLambdaQueryWrapper1);
        emps.forEach(System.out::println);
    }

還有一種構造器,3.0.7新增的:

@Test
    public void queryWrapperLambda22(){
        List<Emp> emps = new LambdaQueryChainWrapper<Emp>(empMapper)
                .like(Emp::getName, "雨")
                .list();
        emps.forEach(System.out::println);
    }

一個實體類泛型,一個mapper介面。最後的list是吧得到的變成list,否則是一個LambdaQueryChainWrapper

條件構造器常用方法

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-WBzUyj20-1605533209759)(C:\Users\cyx\AppData\Roaming\Typora\typora-user-images\image-20200701175511933.png)]

使用條件構造器的自定義sql(版本大於3.0.7)

@Repository
public interface EmpMapper extends BaseMapper<Emp> {

    @Select("select * from emp ${ew.customSqlSegment}")
    List<Emp> selectAll(@Param(Constants.WRAPPER) LambdaQueryWrapper<Emp> wrappers);
}

--------------------------------------------------------------------------------------------
@Test
    public void queryWrapperMy(){
        LambdaQueryWrapper<Emp> empLambdaQueryWrapper1 = Wrappers.<Emp>lambdaQuery();
        empLambdaQueryWrapper1.like(Emp::getName,"雨");
        List<Emp> emps = empMapper.selectAll(empLambdaQueryWrapper1);
        emps.forEach(System.out::println);
    }

細節:@Select裡的${ew.customSqlSegment}是固定寫法,@Param也是

也可以寫在xml中,但是要在主配置檔案中宣告

mybatis-plus:
	mapper-locations:
		- 路徑

xml中

匯入約束略
<mapper namespace="全路徑">
	<select id="" resulttype="">
    	sql語句(寫法和註解裡面一樣的)
    </select>
</mapper>

分頁查詢

物理分頁外掛,寫一個配置類

@MapperScan("com.chuyx.mp.mapper")
@EnableTransactionManagement
@Configuration
public class MyBatatisplusConfig {
    //分頁外掛
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        return paginationInterceptor;
    }
}

呼叫:

@Test
    public void queryPage(){
        LambdaQueryWrapper<Emp> wrapper = Wrappers.<Emp>lambdaQuery().like(Emp::getName, "雨");
        Page<Emp> empPage = new Page<>(1, 2);
        IPage<Emp> empIPage = empMapper.selectPage(empPage, wrapper);
        List<Emp> records = empIPage.getRecords();
        records.forEach(System.out::println);
        System.out.println("總記錄數:"+empIPage.getTotal());
        System.out.println("總頁數:"+empIPage.getPages());
    }

提示:配置類的註解@Configuration

​ 記得將外掛講給Spring容器管理

​ 呼叫時new的Page需要泛型,如上第一個引數是當且頁,第二個引數是條件構造器

​ 查出來是一個IPage,有很多方法,如過去總記錄數,總頁數,過去所有記錄等

原始碼:

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

    /**
     * 根據 Wrapper 條件,查詢全部記錄(並翻頁)
     *
     * @param page         分頁查詢條件
     * @param queryWrapper 實體物件封裝操作類
     */
    IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

selectMapsPage返回值:

​ key為欄位,Object為值

核心功能補充

基礎回憶

orderByDesc(“欄位”):降序排序

orderByASC(“欄位”):升序排序

ps:本文集各類文章(百度百科、SCDN部落格,其他人筆記)加自己理解整合,如有侵權請告知,會立即刪除!

相關文章