認識MyBatis的好兄弟 MyBatis – Plus

  • 2019 年 10 月 4 日
  • 筆記

快速搭建

我們先通過一個簡單的Demo 來認識一下 MyBatis – Plus 的搭建和用法:

現在資料庫中創建一張 User 表,表結構和數據如下

id

name

age

email

1

lx

21

2

cxuan

20

3

liux

28

4

xiaona

21

5

lxuan

24

對應的建表語句和SQL語句如下

DROP TABLE IF EXISTS user;    CREATE TABLE user  (  	id BIGINT(20) NOT NULL COMMENT '主鍵ID',  	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',  	age INT(11) NULL DEFAULT NULL COMMENT '年齡',  	email VARCHAR(50) NULL DEFAULT NULL COMMENT '郵箱',  	PRIMARY KEY (id)  );    INSERT INTO `user` VALUES (1, 'lx', 21, '[email protected]');  INSERT INTO `user` VALUES (2, 'cxuan', 20, '[email protected]');  INSERT INTO `user` VALUES (3, 'liux', 28, '[email protected]');  INSERT INTO `user` VALUES (4, 'xiaona', 21, '[email protected]');  INSERT INTO `user` VALUES (5, 'lxuan', 24, '[email protected]');  

使用 IDEA 新建一個 SpringBoot 項目,構建完成後,在 pom.xml添加如下依賴:

<dependencies>    <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter</artifactId>    </dependency>    <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-test</artifactId>      <scope>test</scope>    </dependency>    <dependency>      <groupId>org.projectlombok</groupId>      <artifactId>lombok</artifactId>      <optional>true</optional>    </dependency>    <dependency>      <groupId>com.baomidou</groupId>      <artifactId>mybatis-plus-boot-starter</artifactId>      <version>3.2.0</version>    </dependency>    <dependency>      <groupId>mysql</groupId>      <artifactId>mysql-connector-java</artifactId>      <version>5.1.38</version>    </dependency>  </dependencies>  

新建 application.yml ,在yml 文件上添加如下資料庫驅動資訊

spring:    datasource:      driver-class-name: com.mysql.jdbc.Driver      url: jdbc:mysql://localhost:3306/mybatis      username: root      password: 123456  

在主方法上添加 @MapperScan 註解,掃描mapper 包下面的內容

@SpringBootApplication  @MapperScan("com.mybatis.plus.mapper")  public class MybatisPlusApplication {        public static void main(String[] args) {          SpringApplication.run(MybatisPlusApplication.class, args);      }    }  

新建一個 User 類,使用 @Data lombok 中的註解,如下

@Data  public class User {        private long id;      private String name;      private Integer age;      private String email;  }  

然後新建一個介面,這個介面實現 BaseMapper介面

public interface UserMapper extends BaseMapper<User> {}  

使用單元測試進行測試:

@RunWith(SpringRunner.class)  @SpringBootTest  public class MybatisPlusApplicationTests {        @Autowired      private UserMapper userMapper;        @Test      public void contextLoads() {          System.out.println("----- selectAll method test -----");          List<User> userList = userMapper.selectList(null);          Assert.assertEquals(5,userList.size());          userList.forEach(System.out::println);      }    }  

輸出:

User(id=1, name=lx, age=21, [email protected]) User(id=2, name=cxuan, age=20, [email protected]) User(id=3, name=liux, age=28, [email protected]) User(id=4, name=xiaona, age=21, [email protected]) User(id=5, name=lxuan, age=24, [email protected])

通過以上幾個簡單的步驟,我們就實現了 User 表的 查詢 功能,你沒有看到一條 SQL 語句和 映射的編寫。

從以上步驟中,我們可以看到集成MyBatis-Plus非常的簡單,只需要引入 starter 工程,並配置 mapper 掃描路徑即可。

特性

  • 無侵入: 只做增強不做改變,引入它不會對現有工程產生影響,如絲般順滑
  • 損耗小: 啟動即會自動注入基本 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、SQLServer2005、SQLServer 等多種資料庫
  • 內置性能分析插件: 可輸出 Sql 語句以及其執行時間,建議開發測試時啟用該功能,能快速揪出慢查詢
  • 內置全局攔截插件: 提供全表 delete 、 update 操作智慧分析阻斷,也可自定義攔截規則,預防誤操作

MyBatis 核心功能

Mapper CRUD 介面

「說明:

  • 通用 CRUD 封裝BaseMapper[1]介面,為 Mybatis-Plus 啟動時自動解析實體表關係映射轉換為 Mybatis 內部對象注入容器
  • 泛型 T 為任意實體對象
  • 參數 Serializable 為任意類型主鍵 Mybatis-Plus 不推薦使用複合主鍵約定,每一張表都有自己的唯一 id 主鍵
  • 對象 Wrapper條件構造器[2]

看下其基本使用

Insert

insert 只有一種用法,直接插入對象的實體

/**   * 插入一條記錄   * @param entity 實體對象   * @return 插入成功記錄數   */  int insert(T entity);  

驗證

我們先為 User 實體類添加 @AllArgsConstructor 註解,如果 Lombok 不熟的同學請移步至 這些極簡的註解你都清楚嗎 這篇文章一探究竟。

下面是測試所用的程式碼

@Test  public void insertUserEntity(){    userMapper.insert(new User(6,"cxuanxuan",25,"[email protected]"));  }  

「注意 Junit 中測試的 insert 插入方法是沒有返回值的,不然會報錯,所以返回類型是void 。但其實 insert 方法是有返回值的,返回的是插入成功的記錄數。

Delete

delete 有四種用法,分別是根據 id 刪除、通過某個表欄位刪除、通過實體類刪除和批量刪除,比我們最初只是通過 id 刪除功能強大很多。

/**   * 根據 ID 刪除   * @param id 主鍵ID   * @return 刪除成功記錄數   */  int deleteById(Serializable id);    /**   * 根據 columnMap 條件,刪除記錄   * @param columnMap 表欄位 map 對象   * @return 刪除成功記錄數   */  int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);    /**   * 根據 entity 條件,刪除記錄   * @param wrapper 實體對象封裝操作類(可以為 null)   * @return 刪除成功記錄數   */  int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);    /**   * 刪除(根據ID 批量刪除)   * @param idList 主鍵ID列表(不能為 null 以及 empty)   * @return 刪除成功記錄數   */  int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);  

驗證

驗證示例如下:

// 根據某個特定的 id 進行刪除。  @Test  public void deleteUserById(){    userMapper.deleteById(6);  }    // deleteByMap 參數是 Map<String, Object> 類型  // 第一個范型是欄位名稱,第二個范型是欄位對應的值  @Test  public void deleteByColumnMap(){    Map<String,Object> columnMap = new HashMap<>();    columnMap.put("id",4);    userMapper.deleteByMap(columnMap);  }    // 使用 QueryWrapper 進行條件篩選  @Test  public void deleteEntity(){    QueryWrapper<User> queryWrapper = new QueryWrapper();    // 刪除 name 不為 null ,並且 age 大於等於 28的記錄    queryWrapper.isNotNull("name").ge("age",28);    userMapper.delete(queryWrapper);  }    // 根據 Collection 集合進行刪除,也可以是 Collection 的子類  @Test  public void deleteBatch(){    List list = new ArrayList();    // 批量刪除 1 和 2 的數據    list.add(1);    list.add(2);    userMapper.deleteBatchIds(list);  }  

上面是 Delete 方法的測試例子,其中 **deleteByColumnMap 和 deleteEntity ** 方法如果不傳任何值,默認刪除表中所有的數據。deleteBatch 如果傳遞 null 的話,測試會報錯,無法通過單元測試。

Update

Update 更新方法只有兩種形式,一種是直接根據 id 修改實體屬性的值,一種是直接更新實體類

/**   * 根據 ID 修改   * @param entity 實體對象   * @return 修改成功記錄數   */  int updateById(@Param(Constants.ENTITY) T entity);    /**   * 根據 whereEntity 條件,更新記錄   * @param entity        實體對象 (set 條件值,可為 null)   * @param updateWrapper 實體對象封裝操作類(可以為 null,裡面的 entity 用於生成 where 語句)   * @return 修改成功記錄數   */  int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);  

驗證

// 根據id更新User表  @Test  public void updateUserById(){    userMapper.updateById(new User(5,"cxuaner",25,"[email protected]"));  }    // 更新 User 實體類資訊  @Test  public void updateUserEntity(){    UpdateWrapper<User> updateWrapper = new UpdateWrapper();    updateWrapper.eq("age",28);    userMapper.update(new User(3,"cxuan",22,"[email protected]"),updateWrapper);  }  
  • 第一條 updateUserById 語句是根據 id 進行更新,傳入一個實體類的意思是更新 id = 5的這條記錄。 傳入 null 會報錯,如果沒有 id = 5的這條記錄,測試會成功,但是不會更新任何記錄
  • 第二條 updateUserEntity 語句是根據實體類的條件進行更新,UpdateWrapper 是一個條件構造器,測試的是 age 為 28 的這條記錄進行更新。 條件構造器後面會進行更加詳細的介紹。

Select

Select 用法比較多,現在來一起看一下Select 有哪些用法

/**   * 根據 ID 查詢   * @param id 主鍵ID   * @return 實體   */  T selectById(Serializable id);    /**   * 查詢(根據ID 批量查詢)   * @param idList 主鍵ID列表(不能為 null 以及 empty)   * @return 實體集合   */  List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);    /**   * 查詢(根據 columnMap 條件)   * @param columnMap 表欄位 map 對象   * @return 實體集合   */  List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);    /**   * 根據 entity 條件,查詢一條記錄   * @param queryWrapper 實體對象   * @return 實體   */  T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);    /**   * 根據 Wrapper 條件,查詢總記錄數   * @param queryWrapper 實體對象   * @return 滿足條件記錄數   */  Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);    /**   * 根據 entity 條件,查詢全部記錄   * @param queryWrapper 實體對象封裝操作類(可以為 null)   * @return 實體集合   */  List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);    /**   * 根據 Wrapper 條件,查詢全部記錄   * @param queryWrapper 實體對象封裝操作類(可以為 null)   * @return 欄位映射對象 Map 集合   */  List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);    /**   * 根據 Wrapper 條件,查詢全部記錄   * 注意:只返回第一個欄位的值   * @param queryWrapper 實體對象封裝操作類(可以為 null)   * @return 欄位映射對象集合   */  List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);    /**   * 根據 entity 條件,查詢全部記錄(並翻頁)   * @param page         分頁查詢條件(可以為 RowBounds.DEFAULT)   * @param queryWrapper 實體對象封裝操作類(可以為 null)   * @return 實體分頁對象   */  IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);    /**   * 根據 Wrapper 條件,查詢全部記錄(並翻頁)   * @param page         分頁查詢條件   * @param queryWrapper 實體對象封裝操作類   * @return 欄位映射對象 Map 分頁對象   */  IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);  

驗證

下面就對上面的示例方法進行驗證

/**  * 查詢id = 1 的一條記錄  */  @Test  public void selectById(){    User user = userMapper.selectById(1);    System.out.println("user = " + user);  }    /**  * 批量查詢id = 1,2,3 的記錄  */  @Test  public void selectUserBatchId(){    List batchIds = new ArrayList();    batchIds.add(1);    batchIds.add(2);    batchIds.add(3);    List list = userMapper.selectBatchIds(batchIds);    System.out.println("list = " + list);  }    /*  * 查詢年齡為 21 歲的記錄,並循環遍歷輸出  */  @Test  public void selectUserByMap(){    Map<String,Object> userMap = new HashMap<>();    userMap.put("age",21);    List<User> users = userMapper.selectByMap(userMap);    users.forEach(p-> {      System.out.println(p);    });  }    /**  * 根據 entity 條件,查詢一條id = 1 的記錄,需要手動添加 User(long id)的構造器  */  @Test  public void selectOneUser(){      // 需要在 User 類上添加一個 id 的構造函數    User user = userMapper.selectOne(new QueryWrapper<>(new User(1)));    System.out.println("user = " + user);  }    /**  * 根據 Wrapper 條件,查詢年齡大於 22 的總條目數  */  @Test  public void selectCountNum(){    QueryWrapper<User> queryWrapper = new QueryWrapper();    queryWrapper.ge("age",22);    Integer integer = userMapper.selectCount(queryWrapper);    System.out.println("查詢出來的總記錄數 = " + integer);  }    /*  * 查詢年齡大於22 的所有記錄數,返回一個List  */  @Test  public void selectUserList(){    QueryWrapper<User> queryWrapper = new QueryWrapper();    queryWrapper.ge("age",22);    List<User> users = userMapper.selectList(queryWrapper);    users.forEach(p-> {      System.out.println(p);    });  }    /*  * 查詢年齡大於22 的所有記錄數,返回的是一個List<Map>  */  @Test  public void selectUserMaps(){    QueryWrapper<User> queryWrapper = new QueryWrapper();    queryWrapper.ge("age",22);    List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);    maps.forEach(p-> {      System.out.println(p);    });  }    /**  * 查詢年齡大於22 的所有記錄數,返回的是一個List<Object>  * 注意:只返回第一個欄位的值  */  @Test  public void selectUserObject(){    QueryWrapper<User> queryWrapper = new QueryWrapper();    queryWrapper.ge("age",22);    List<Object> objects = userMapper.selectObjs(queryWrapper);    objects.forEach(p-> {      System.out.println(p);    });  }  

參考資料

[1]

BaseMapper: https://gitee.com/baomidou/mybatis-plus/blob/3.0/mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/mapper/BaseMapper.java

[2]

條件構造器: https://mp.baomidou.com/guide/wrapper.html