MyBatis Plus 增刪改查 (三)

1. CURD方法參數與返回值說明

理解了方法參數與返回值,各個增刪改查方法都是大同小異,都是各種重載方法。

1.1 方法參數

  • @Param(Constants.WRAPPER) Wrapper<T> queryWrapper
    • @Param作用是給參數起別名,以便在mybatis語句中的佔位符使用(瞭解即可)
    • Constants.WRAPPER是常量,每個常量有不同的名字(瞭解即可)
    • Wrapper< T >是條件構造器,可以根據實體對象的默認情況下非null屬性作等值比較,多個條件會自動用and連接,如果queryWrapper參數爲null,則表示不添加條件(即查詢所有記錄)
    • 條件構造器也可以自身的方法動態添加條件,詳情參考後面
    • @TableField註解中的condition 可以改變比較類型,whereStrategy可以改變屬性是否作爲條件的判斷
FieldStrategy常量 描述
IGNORED 忽略判斷,不建議使用,如果屬性值爲null,只會用=比較,不會用is,查詢結果不對
NEVER 從不作爲條件
NOT_NULL 非NULL判斷,默認值
NOT_EMPTY 非空判斷(只對字符串類型字段,其他類型字段依然爲非NULL判斷)
DEFAULT 追隨全局配置
SqlCondition常量 描述
EQUAL 等於column=value,默認值
NOT_EQUAL 不等於column<>value
LIKE 左右模糊查詢,column like ‘%value%’
LIKE_LEFT 左模糊查詢,column like ‘%value’
LIKE_RIGHT 右模糊查詢,column like ‘value%’

實體屬性註解設置

// condition = SqlCondition.LIKE 字符串模糊查詢
// whereStrategy=FieldStrategy.NOT_EMPTY  字符串爲null或""則不會作爲條件,注意空格會作爲條件
@TableField(condition = SqlCondition.LIKE, whereStrategy=FieldStrategy.NOT_EMPTY)
private String bookName;

Wrapper參數測試

//構造條件實體對象
Book book = new Book();
book.setCategoryId(4);   //非null屬性作等值比較 category_id=4
book.setBookPrice(null); //默認情況下null值屬性不會作爲默認值
book.setBookName("書籍");  //bookName屬性上設置了SqlCondition.LIKE,所以不再是等值比較,而是like

//創建Wrapper,並把實體對象傳遞構造函數中
QueryWrapper<Book> wrapper = new QueryWrapper<>(book);

//SELECT * FROM book WHERE book_name LIKE CONCAT('%',?,'%') AND category_id=?
List<Book> bookList = bookService.list(wrapper);
bookList.forEach(System.out::println);

//SELECT * FROM book WHERE category_id=?
System.out.println("==========================空字符串============================");
book.setBookName("");  //bookName屬性上設置了FieldStrategy.NOT_EMPTY,null值與空字符串都不會作爲條件
bookList = bookService.list(wrapper);
bookList.forEach(System.out::println);

//SELECT * FROM book WHERE book_name LIKE CONCAT('%',?,'%') AND category_id=?
System.out.println("=============================空格=========================");
book.setBookName("  ");  //bookName屬性即使設置了FieldStrategy.NOT_EMPTY,空格也會作爲條件
bookList = bookService.list(wrapper);
bookList.forEach(System.out::println);

//SELECT * FROM book 
System.out.println("=======================Wrapper爲null======================");
bookList = bookService.list(null);   //Wrapper爲null則不添加條件
bookList.forEach(System.out::println);
  • @Param(Constants.COLUMN_MAP) Map<String, Object> columnMap
    • 把每個鍵值對作等值比較,多個條件會自動用and連接,key必須是數據庫的列名,而不是實體的屬性名;如果value爲null也會作爲條件key is null
    • @TableField對columnMap無效,因爲columnMap直接操作的是數據庫表的列
//構造Map條件
Map<String,Object> map=new HashMap<>();
map.put("category_id",4);  //key值必須是列名,否則會報錯  category_id=4
map.put("book_name",null);  // value爲null也會作爲條件,  book_name is null

//SELECT * FROM book WHERE category_id = ? AND book_name IS NULL 
List<Book> list = bookMapper.selectByMap(map);
  • @Param(Constants.COLLECTION) Collection<? extends Serializable> idList
    • idList是主鍵值集合
//構建主鍵集合
List<Integer> idList = Arrays.asList(1, 3, 6);

//SELECT  FROM book WHERE book_id IN ( ? , ? , ? )
List<Book> bookList = bookMapper.selectBatchIds(idList);
bookList.forEach(System.out::println);
  • IPage<T> page
    • page是分頁對象,用於分頁查詢
    • 分頁操作需要配置分頁插件,不能單純調用方法,詳情參考3.8
//構建Page分頁對象,第一參數是當前頁碼,第二參數是每頁顯示的記錄數,
//第三參數是否執行count語句,默認爲true,如果只查詢數據可以把參數設爲false
Page page=new Page(1,2,true);


//SELECT * FROM book LIMIT ?,?
Page<Book> bookPage = bookMapper.selectPage(page,null);
  • Function<? super Object, V> mapper (可直接忽略,幾乎不用)
    • 函數接口,定義了一個單個方法參數帶返回值的方法,比如 V method(Object obj),結果集在封裝每一行數據後都會調用該函數接口的方法,把結果集的當前行記錄的主鍵值作爲實參值傳遞進方法中
    • 使用Lambda表達式實現函數接口的方法,根據傳遞的主鍵值做一些額外的操作
//必須有返回值,obj是主鍵值,Object類型,如需根據主鍵值刪改查,需要強制轉換爲Serializable
Function function= obj->{
    if(obj!=null) {
        //獲取主鍵值
        Serializable id = (Serializable) obj;
        
		/* 此處可以根據主鍵值id進行一系列的額外操作 */
		// xxxService.getById(id);
		// xxxService.deleteById(id);
		// xxxService.updateById(id);
		
		//返回值可以根據實際返回任何數據
        return  id;
    }
    return null;
};

//SELECT * FROM book
//Function的返回值類型V,而listObjs返回值類型List<V>,因爲結果集有多行記錄
//<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
List<Serializable> list = bookService.listObjs(null, function);

1.2 返回值

  • int

    • 執行sql語句後受影響的行數
  • boolean

    • sql語句是否執行成功
  • List<Map<String, Object>>

    • 每行記錄爲Map,列名爲key,列值爲value
  • List<Object>

    • 只返回第一列的數據
  • Collection<T>

    • 跟List< T >一樣
  • IPage<T>

    • 封裝了分頁信息和分頁查詢記錄
    • 分頁操作需要配置分頁插件,不能單純調用方法,詳情參考3.8
//構建Page分頁對象
Page page=new Page(1,2);

//SELECT * FROM book LIMIT ?,?
Page<Book> bookPage = bookMapper.selectPage(page,null);
//bookPage與page是一樣的
System.out.println(page==bookPage);  //輸出true

List<Book> bookList = bookPage.getRecords();  //當前分頁查詢返回的記錄
long totalRows=bookPage.getTotal();  //總記錄數
long totalPage=bookPage.getPages();  //總頁數

2. BaseMapper CURD接口

2.1 查詢

方法說明

// 根據主鍵查詢單條記錄
T selectById(Serializable id);

// 根據 Wrapper 條件,查詢一條記錄返回單個實體對象
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根據主鍵集合查詢多條記錄返回對象集合
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

// 根據 Wrapper 條件,查詢多條記錄返回對象集合
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根據 columnMap 條件,查詢多條記錄返回對象集合
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

// 根據 Wrapper 條件,查詢多條記錄返回Map集合,每行記錄爲Map,列名爲key,列值爲value
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根據 Wrapper 條件,查詢多條記錄。注意: 只返回第一個列的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 條件分頁查詢,返回對象集合類型的IPage
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 條件分頁查詢,返回Map類型的IPage
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根據 Wrapper 條件,查詢總記錄數
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

測試例子

//根據Wrapper條件查詢所有記錄,返回對象集合
//SELECT * FROM book 
//這裏Wrapper參數爲null,則不會添加條件
List<Book> bookList = bookMapper.selectList(null);


//根據Wrapper條件查詢返回單條記錄
//SELECT * FROM book WHERE book_id=?
Book book=new Book();
book.setBookId(1);
book.setBookName(null);  //null值的屬性不會作爲條件
Book book2 = bookMapper.selectOne(new QueryWrapper<>(book));


//根據Map條件查詢並返回對象集合
//SELECT * FROM book WHERE category_id = ? AND book_date IS NULL 
Map<String,Object> conditionMap=new HashMap<String,Object>();
//這裏的key要用數據庫表Book的列名,而不是用Book實體類的categoryId丶bookDate
conditionMap.put("category_id",1);
conditionMap.put("book_date",null);
List<Book> bookList = bookMapper.selectByMap(conditionMap);
bookList.forEach(System.out::println);


//根據Wrapper條件查詢所有記錄,並返回Map集合
//SELECT * FROM book 
List<Map<String, Object>> mapList = bookMapper.selectMaps(null);
//遍歷每行記錄
for (Map<String,Object> map : mapList) {
    //遍歷每列
    for (String key : map.keySet()) {
        System.out.println("key:"+key+",value:"+map.get(key));
    }
}

2.2 增加

方法說明

// 插入一條記錄,返回受影響的行數(>0表示插入成功),方法執行完後會自動把主鍵值賦值到實體的主鍵屬性上,null值屬性不會插入到數據庫
int insert(T entity);

測試例子

//INSERT INTO book ( book_name, book_price ) VALUES ( ?, ? ) 
Book book=new Book();
book.setBookName("書籍03");
book.setBookPrice(BigDecimal.valueOf(10.3));
book.setBookDate(null);  //null值屬性不會插入到數據庫

int result= bookMapper.insert(book);
if(result>0){
    System.out.println("插入成功");
    System.out.println(book);  //插入成功後book對象有主鍵值
}else{
    System.out.println("插入失敗");
}

2.3 修改

方法說明

// 根據 Wrapper條件,更新記錄,返回受影響的行數,null屬性不會更新到數據庫
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);

// 根據實體的主鍵值更新記錄,返回受影響的行數,null屬性不會更新到數據庫
int updateById(@Param(Constants.ENTITY) T entity);

測試例子

//根據Wrapper條件更新記錄
//UPDATE book SET book_price=? WHERE category_id=? 
//需要更新的實體類
Book book=new Book();
//把書籍價格都設置爲100
book.setBookPrice(BigDecimal.valueOf(100));
book.setBookDate(null);  //null值屬性不會更新到數據庫

//條件實體類
Book conditionBook=new Book();
conditionBook.setCategoryId(4);
conditionBook.setBookName(null); //null值屬性不會作爲條件

int result= bookMapper.update(book,new UpdateWrapper<>(conditionBook));


//根據實體主鍵值更新記錄
//UPDATE book SET book_name=? WHERE book_id=? 
//需要更新的實體類
Book book=new Book();
book.setBookId(10);  //設置主鍵值
book.setBookName("修改後的書籍名");
book.setBookDate(null);  //null值屬性不會更新到數據庫

int result= bookMapper.updateById(book);

2.4 刪除

方法說明

// 根據 Wrapper條件,刪除記錄,返回受影響的行數
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);

// 刪除主鍵集合批量刪除記錄,返回受影響的行數
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

// 根據主鍵值刪除單條記錄,返回受影響的行數
int deleteById(Serializable id);

// 根據 columnMap 條件,刪除記錄,返回受影響的行數
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

測試例子

//根據主鍵值集合刪除多條記錄
//DELETE FROM book WHERE book_id IN ( ? , ? ) 
//設置主鍵值集合
List<Serializable> ids=new ArrayList<>();
ids.add(14);
ids.add(15);
int result=bookMapper.deleteBatchIds(ids);


//根據Wrapper條件刪除多條記錄
//DELETE FROM book WHERE book_name=? AND category_id=? 
Book book=new Book();
book.setCategoryId(6);
book.setBookName("書籍02");
book.setBookDate(null);  //null屬性不會作爲條件
int result=bookMapper.delete(new QueryWrapper<>(book));

3. ServiceImpl CURD接口

3.1 Get查詢單條記錄

方法說明

// 根據主鍵查詢單條記錄
T getById(Serializable id);

// 根據 Wrapper,查詢單條記錄,如果結果集返回多條記錄,則會拋出異常
T getOne(Wrapper<T> queryWrapper);

// 根據 Wrapper,查詢單條記錄; 如果結果集返回多條記錄,throwEx參數值爲
// true,則拋出異常,throwEx爲false,則返回結果集中的第一條記錄
T getOne(Wrapper<T> queryWrapper, boolean throwEx);

// 根據 Wrapper,查詢單條記錄,返回Map集合,列名爲key,列值爲value
Map<String, Object> getMap(Wrapper<T> queryWrapper);

// 根據 Wrapper,查詢一條記錄
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

測試例子

// SELECT * FROM book WHERE category_id=? 
Book book=new Book();
book.setCategoryId(4);
//該結果集返回了多條記錄,throwEx爲false,所以不會拋出異常,會把結果集中的第一條數據返回
Book b = bookService.getOne(new QueryWrapper<>(book),false);

3.2 List查詢多條記錄

方法說明

// 查詢所有
List<T> list();

// 根據Wrapper條件查詢多條記錄
List<T> list(Wrapper<T> queryWrapper);

// 根據主鍵值集合查詢多條記錄
Collection<T> listByIds(Collection<? extends Serializable> idList);

// 根據 columnMap 條件查詢多條記錄
Collection<T> listByMap(Map<String, Object> columnMap);

// 查詢所有記錄,返回List<Map>集合,每行記錄爲Map,列名爲key,列值爲value
List<Map<String, Object>> listMaps();

// 根據Wrapper條件查詢多條記錄,返回List<Map>集合,每行記錄爲Map,列名爲key,列值爲value
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);

// 查詢所有記錄,只返回第一列的數據
List<Object> listObjs();

// 對所有查詢結果進行額外的操作(可忽略)
<V> List<V> listObjs(Function<? super Object, V> mapper);

// 根據 Wrapper 條件,查詢所有記錄,值返回第一列的數據
List<Object> listObjs(Wrapper<T> queryWrapper);

// 根據 Wrapper 條件查詢多條記錄,對查詢結果進行額外的操作(可忽略)
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

3.3 Count查詢記錄數

方法說明

// 查詢總記錄數
int count();

// 根據 Wrapper 條件,查詢總記錄數
int count(Wrapper<T> queryWrapper);

3.4 save新增數據

方法說明

// 插入一條記錄
boolean save(T entity);

// 批量插入多條記錄,每插入一條記錄執行一次insert語句
boolean saveBatch(Collection<T> entityList);

// 批量插入多條記錄,每隔batchSize條記錄執行一次insert語句(性能稍高)
boolean saveBatch(Collection<T> entityList, int batchSize);

測試例子

//創建5個Book對象放進List集合中
List<Book> bookList=new ArrayList<>();
for (int i = 1; i <=5 ; i++) {
    Book book=new Book();
    book.setBookName("書籍"+i);
    bookList.add(book);
}

// insert語句執行次數=向上取整(bookList元素數量/batchSize)
bookService.saveBatch(bookList, 3);

3.5 update修改數據

方法說明

// 以updateWrapper作爲update語句的where條件
// 該方法必須updateWrapper調用set()來設置需要更新的列和值
boolean update(Wrapper<T> updateWrapper);

// 以updateWrapper作爲update語句的where條件
// 以entity作爲需要更新的列和值,默認情況下null值屬性不會被更新
boolean update(T entity, Wrapper<T> updateWrapper);

// 以主鍵作爲update語句的where條件
// 以entity作爲需要更新的列和值,默認情況下null值屬性不會被更新
// 主鍵必須有值,如果值爲null,條件會變成book_id=null
boolean updateById(T entity);

// 根據實體集合的主鍵值批量更新,每隔1條記錄執行一次update語句
boolean updateBatchById(Collection<T> entityList);

// 根據實體集合的主鍵值批量更新,每隔batchSize條記錄執行一次update語句(性能稍高)
boolean updateBatchById(Collection<T> entityList, int batchSize);

測試例子

/*** 以主鍵爲條件,以實體對象作爲更新的列和值 ***/
Book book=new Book();
book.setBookId(41);  //主鍵必須有值,如果值爲null,條件會變成book_id=null
book.setBookPrice(BigDecimal.valueOf(60));
book.setBookDate(LocalDateTime.now());

// UPDATE book SET book_date=?, book_price=? WHERE book_id=?
bookService.updateById(book);



/*** 以updateWrapper爲條件,自定義set需要更新的列和值 ***/
// 構建update語句的where條件
Book conditionBook=new Book();
conditionBook.setCategoryId(7);
UpdateWrapper<Book> updateWrapper=new UpdateWrapper(conditionBook);

// 必須設置更新的列和值,即update語句的set關鍵字後面那部分
updateWrapper.set("book_price",50);
updateWrapper.set("book_date", LocalDateTime.now());

// UPDATE book SET book_price=?,book_date=? WHERE category_id=? 
bookService.update(updateWrapper);



/*** 以updateWrapper爲條件,以實體對象作爲更新的列和值 ***/
// 構建update語句的where條件
Book conditionBook=new Book();
conditionBook.setCategoryId(7);
UpdateWrapper<Book> updateWrapper=new UpdateWrapper(conditionBook);

// 構建update語句的set後面部分
Book book=new Book();
book.setBookPrice(BigDecimal.valueOf(60));
book.setBookDate(LocalDateTime.now());

// UPDATE book SET book_price=?,book_date=? WHERE category_id=?
bookService.update(book,updateWrapper);

3.6 saveOrUpdate 根據主鍵值修改或新增

方法說明

// 如果實體主鍵不爲null,則進行更新操作
// 如果實體主鍵爲null,則進行新增操作
// 更新與新增的方法說明請查看3.4與3.5
boolean saveOrUpdate(T entity);
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
boolean saveOrUpdateBatch(Collection<T> entityList);
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);

測試例子

Book book=new Book();
book.setBookId(41);  //主鍵值不爲null執行修改更新操作
book.setBookPrice(BigDecimal.valueOf(80));
book.setBookDate(LocalDateTime.now());

// SELECT * FROM book WHERE book_id=?      //比update方法多了一個查詢語句 ?????
// UPDATE book SET book_date=?, book_price=? WHERE book_id=?
bookService.saveOrUpdate(book);

book.setBookId(null);  //主鍵值爲null執行插入新增操作
// INSERT INTO book ( book_date, book_price ) VALUES ( ?, ? ) 
bookService.saveOrUpdate(book);
System.out.println(book);

3.7 remove 刪除記錄

方法說明

// 根據queryWrapper條件刪除多條記錄
boolean remove(Wrapper<T> queryWrapper);
// 根據主鍵值刪除單條記錄
boolean removeById(Serializable id);
// 根據 columnMap 條件刪除多條記錄
boolean removeByMap(Map<String, Object> columnMap);
// 根據主鍵集合刪除多條記錄
boolean removeByIds(Collection<? extends Serializable> idList);

3.8 Page 分頁查詢

  • 配置分頁插件
    • 新建一個com.config包(包名隨意)
    • 在com.config包中新建MybatisPlusConfig類
    • 複製以下代碼
package com.config;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

//Spring boot方式
@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 設置請求的頁面大於最大頁後操作, true調回到首頁,false 繼續請求  默認false
        // paginationInterceptor.setOverflow(false);
        // 設置最大單頁限制數量,默認 500 條,-1 不受限制
        // paginationInterceptor.setLimit(500);
        // 開啓 count 的 join 優化,只針對部分 left join
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        return paginationInterceptor;
    }
}

方法說明

// 無條件分頁查詢,返回Page對象,封裝的數據是List<T>類型
IPage<T> page(IPage<T> page);

// 條件分頁查詢,返回Page對象,封裝的數據是List<T>類型
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);

// 無條件分頁查詢,返回Page對象,封裝的數據是List<Map<String, Object>>類型
IPage<Map<String, Object>> pageMaps(IPage<T> page);

// 條件分頁查詢,返回Page對象,封裝的數據是List<Map<String, Object>>類型
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);

測試例子

//構建Page分頁對象,第一參數是當前頁碼,第二參數是每頁顯示的記錄數,第三參數是否執行count語句,默認爲true
Page page=new Page(1,2);

// SELECT COUNT(1) FROM book   //Page構造函數的第三個參數指定是否執行該語句
// SELECT * FROM book LIMIT ?,?
Page<Book> bookPage = bookService.page(page);

//bookPage與page是一樣的
System.out.println(page==bookPage);  //輸出true

List<Book> bookList = bookPage.getRecords();  //當前分頁查詢返回的記錄

//執行了count語句,總記錄數和總頁數才能正確計算,否則值都爲0
long totalRows=bookPage.getTotal();  //總記錄數
long totalPage=bookPage.getPages();  //總頁數

System.out.println(totalRows);
System.out.println(totalPage);
bookList.forEach(System.out::println);

  • 自定義分頁
public interface BookMapper extends BaseMapper<Book> {
	// 普通的查詢語句
    @Select("select * from book where book_name like #{bookName} and category_id=#{categoryId}")
    // IPage method(Page<?> page,sql語句參數...) 把普通查詢變成分頁查詢
    IPage<Book> findByPage(Page<?> page, String bookName,Integer categoryId);
}
//測試自定義分頁
Page page=new Page(2,3);
bookMapper.findByPage(page,"%書籍%",4);
System.out.println(page.getTotal());
System.out.println(page.getPages());
page.getRecords().forEach(System.out::println);

3.9 Chain 鏈式方法

鏈式方法:Service實現類可以直接調用條件構造器的方法進行條件拼接,最後再調用特定的改查方法

方法說明

  • 條件構造器詳情請查看4
// 下面4個類都可以調用條件構造器的方法
// Lambda開頭的類支持Lambda表達式構造條件,避免列名與實體屬性名不一致的問題

// 鏈式查詢 普通
QueryChainWrapper<T> query();
// 鏈式查詢 lambda 式。注意:不支持 Kotlin
LambdaQueryChainWrapper<T> lambdaQuery(); 

// 鏈式更改 普通
UpdateChainWrapper<T> update();
// 鏈式更改 lambda 式。注意:不支持 Kotlin 
LambdaUpdateChainWrapper<T> lambdaUpdate();
//QueryChainWrapper類與LambdaQueryChainWrapper特有方法
List<T> list()  //查詢多條記錄
T One()         //查詢單條記錄,如果查詢結果有多條記錄,則會報錯

//UpdateChainWrapper與LambdaUpdateChainWrapper特有方法
boolean update()  //修改記錄,必須設置set後面的語句
boolean update(T t)  //修改記錄,以實體對象的非null屬性作爲需要修改的列和值

測試例子

// Service實現類轉換成QueryChainWrapper
// 調用了條件構造器方法拼接查詢條件 category_id=4 and book_price<200
// 最後調用QueryChainWrapper特有方法list()查詢多條記錄
// SELECT * FROM book WHERE (category_id = ? AND book_price < ?) 
List<Book> bookList = bookService.query().eq("category_id", 4).lt("book_price", 200).list();

// Service實現類轉換成LambdaQueryChainWrapper
// 調用了條件構造器方法拼接查詢條件 book_id=1
// 最後調用LambdaQueryChainWrapper特有方法one()查詢單條記錄
// SELECT * FROM book WHERE (book_id = ?)
Book b = bookService.lambdaQuery().eq(Book::getBookId, 1).one();

// Service實現類轉換成UpdateChainWrapper
// 調用了條件構造器方法拼接修改條件 book_id=40
// 最後調用UpdateChainWrapper特有方法update()修改記錄
// 因爲update()方法是無參的,所以必須通過set()設置要修改的列和值 set book_price=500
// UPDATE book SET book_price=? WHERE (book_id = ?)
bookService.update().set("book_price",500).eq("book_id",40).update();

// Service實現類轉換成LambdaUpdateChainWrapper
// 調用了條件構造器方法拼接修改條件 book_id=40
// 最後調用LambdaUpdateChainWrapper特有方法update(entity)修改記錄
// 因爲update(entity)傳遞了實體對象,所以直接根據entity的非null屬性作爲更新的列和值,不用再額外調用set()方法
// UPDATE book SET book_price=? WHERE (book_id = ?) 
Book book=new Book();
book.setBookPrice(BigDecimal.valueOf(500));
bookService.lambdaUpdate().eq(Book::getBookId,40).update(book);

4. 條件構造器

主要作用是拼接where條件,其次作用是設置sql語句中與列相關的部分

4.1 條件合併

  • 計算Wrapper的條件結果後再與Entity條件用and拼接,即多個Entity屬性條件 and (多個Wrapper方法條件),兩種條件是相互獨立的
//實體對象設置2個條件 book_name like '%書籍%' and book_price=100
Book book=new Book();
book.setBookName("書籍"); //因爲實體類上用了註解,所以這裏是模糊查詢
book.setBookPrice(BigDecimal.valueOf(100));

QueryWrapper<Book> queryWrapper=new QueryWrapper<>(book);

//Wrapper設置兩個條件  category_id=4 or category_id=7
queryWrapper.eq("category_id",4).or().eq("category_id",7);

//SELECT * FROM book WHERE book_name LIKE CONCAT('%',?,'%') AND book_price=? AND (category_id = ? OR category_id = ?)
List<Book> bookList = bookService.list(queryWrapper);

//Wrapper條件的小括號()保證了查詢結果的準確性
bookList.forEach(System.out::println);

4.2 AbstractWrapper的常用子類

在這裏插入圖片描述

  • Query是查詢,Update是修改
  • Lambda是把R column參數變成SFunction<T, ?>,Lambda避免手動輸錯列名;普通方式 .eq("book_price",100) Lambda方式 .eq(Book::getBookPrice,100)
  • Chain是從Service接口中獲取Wrapper以便可以調用條件構造器的方法

4.3 AbstractWrapper

子類:QueryWrapper、LambdaQueryWrapper、QueryChainWrapper、LambdaQueryChainWrapper、UpdateWrapper、LambdaUpdateWrapper、UpdateChainWrapper、LambdaUpdateChainWrapper

通用參數說明

  • boolean condition

    • 表示該條件是否加入最後生成的sql中,默認爲true
    • 每個方法的重載方法的第一個參數都有condition參數,所以後面不再展示帶有condition參數的方法
  • R column

    • 比較條件的數據庫表的列名,不是實體屬性名
  • Object val

    • 比較條件的值
  • Consumer<Param> consumer

    • Consumer是一個函數類,用Lambda表達式實現該函數的抽象方法,抽象方法的方法參數傳遞是Wrapper,在方法內用Wrapper可構建多個條件,最終多個條件外面會用小括號()包住
    • 注意:Wrapper創建時必須指定實際泛型,否則調用Consumer參數的方法時傳遞進Lambda表達式的Wrapper是Object類型而不是Wrapper類型
    • 具體例子參考後面的or

方法說明

  • 單個列等值比較
eq(R column, Object val)   //相等 =
ne(R column, Object val)   //不等 <>
gt(R column, Object val)   //大於 >
ge(R column, Object val)   //大於等於 >=
lt(R column, Object val)   //小於 <
le(R column, Object val)   // 小於等於
  • 多個列等值比較
/* 多個條件進行等值比較,null值用value is null作爲條件,用and連接每個條件 */
allEq(Map<R, V> params)  
allEq(Map<R, V> params, boolean null2IsNull)

參數說明:
Map<R, V> params Map的key爲R column,value爲Object val
boolean null2IsNull null值是否作爲條件,默認爲true,條件爲val is null;如果爲false,則忽略列值爲null的條件

//構造多個條件
Map<String, Object> map = new HashMap<>();
map.put("category_id", 4);
map.put("book_name",null);

QueryWrapper<Book> queryWrapper = new QueryWrapper<>();
queryWrapper.allEq(map);  //多個條件比較

// SELECT * FROM book WHERE (category_id = ? AND book_name IS NULL) 
List<Book> bookList = bookService.list(queryWrapper);
  • between
//column between val1 and val2
between(R column, Object val1, Object val2)

//column not between val1 and val2
notBetween(R column, Object val1, Object val2)
  • like
like(R column, Object val)  // column like '%val%'
notLike(R column, Object val)  // column not like '%val%'
likeLeft(R column, Object val) // column like '%val'
likeRight(R column, Object val) // column like 'val%'
  • isNull
isNull(R column)  // column is null
isNotNull(R column) // column is not null
  • in
in(R column, Collection<?> value)  //column in (value1,value2,...)
notIn(R column, Collection<?> value) //column not in (value1,value2,...)
inSql(R column, String inSql) // column in (自定義sql片段)
notInSql(R column, String inSql) //column not in (自定義sql片段)

參數說明:
Collection<?> value 多個比較條件值,每個值放進集合中
inSql sql語句中比較條件in關鍵字後添加自定義的sql片段(注意防注入)

// category_id IN (1,2,3,4)
wrapper.in("category_id", Arrays.asList(1,2,3,4));

//category_id in (select category_id from book where book_price>100)
wrapper.inSql("category_id","select category_id from book where book_price>100");
  • exists
exists(String existsSql)
notExists(String existsSql)

參數說明:
existsSql exists關鍵字後面的sql片段,注意防注入

//SELECT * FROM book WHERE (EXISTS (select book_id from book where book_name='西遊記')) 
wrapper.exists("select book_id from book where book_name='西遊記'");
  • group by
groupBy(R... columns)  // group by column1,column2,...
  • having
having(String sqlHaving, Object... params) 

參數說明:
sqlHaving having關鍵字後面的sql片段,可用下標占位符,從0開始
params having條件sql語句中的佔位符實際參數值

QueryWrapper<Book> wrapper=new QueryWrapper();
wrapper.select("category_id");
wrapper.groupBy("category_id");
wrapper.having("count(*)>{0} and count(*)<{1}",3,7);

// SELECT category_id FROM book GROUP BY category_id HAVING count(*)>3 and count(*)<7
List list = bookService.listObjs(wrapper);
list.forEach(System.out::println);
  • order by
orderByAsc(R... columns)  // order by column1 asc,column2 asc,... asc
orderByDesc(R... columns) // order by column1 desc,column2 desc,... desc
orderBy(boolean condition, boolean isAsc, R... columns) //不要用,麻煩
  • or
//主動調用or()表示【緊接着下一個方法】條件用or連接,否則用and連接
or() 

// or嵌套
//or(w-> w.eq("name", "李白").ne("status", "活着"))--->or (name = '李白' and status <> '活着')
or(Consumer<Param> consumer)
// or()只對緊鄰下一個方法的拼接條件有效
// category_id = 1 OR category_id = 4 AND book_price > 50 AND book_price < 150
wrapper.eq("category_id",1).or().eq("category_id",4).gt("book_price",50).lt("book_price",150);



//調用帶Consumer<Param>方法參數的方法時,必須聲明Wrapper時必須指定實際泛型,否則直接爆紅編譯錯誤
QueryWrapper<Book> wrapper=new QueryWrapper();

wrapper.gt("category_id",1);
//w就是QueryWrapper<Book>對象wrapper,or方法裏面的條件最終會被小括號()包住
wrapper.or(w -> w.gt("book_price",50).lt("book_price",200));
wrapper.lt("category_id",1);

// SELECT * FROM book WHERE (category_id > ? OR (book_price > ? AND book_price < ?) AND category_id < ?) 
List<Book> bookList = bookService.list(wrapper);
bookList.forEach(System.out::println);
  • and
// and嵌套,具體用法看or
//and(w-> w.eq("name", "李白").ne("status", "活着"))--->and (name = '李白' and status <> '活着')
and(Consumer<Param> consumer)
  • nested
// 不帶連接關鍵字的嵌套,具體用法看or
//nested(w-> w.eq("name", "李白").ne("status", "活着"))--->(name = '李白' and status <> '活着')
nested(Consumer<Param> consumer)
  • last
//無視優化規則直接拼接到 sql 的最後
//只能調用一次,多次調用以最後一次爲準 有sql注入的風險,請謹慎使用
last(String lastSql)
  • last
// 自定義sql條件,可以用下標占位符(從0開始)防止sql注入
apply(String applySql, Object... params)
//book_price>50 and book_price<100
wrapper.apply("book_price>{0} and book_price<{1}",50,100);

4.4 QueryWrapper

  • 特有方法
select(String... sqlSelect)  //查詢包含指定列
select(Predicate<TableFieldInfo> predicate)  //根據實體屬性篩選查詢列
select(Class<T> entityClass, Predicate<TableFieldInfo> predicate) //根據實體屬性篩選查詢列
lambda() // QueryWrapper轉換爲LambdaQueryWrapper

參數說明:
Predicate<TableFieldInfo> predicate Lambda表達式,傳遞的參數是實體屬性TableFieldInfo,Lambda返回值爲true則表示該屬性會作爲查詢列

// 1個方法參數可以指定多列,多個參數最終會以逗號合併
// SELECT book_name,book_price,book_date FROM book
wrapper.select("book_name,book_price","book_date");



// 調用帶參數Predicate<TableFieldInfo>必須聲明Wrapper的實參泛型
QueryWrapper<Book> wrapper=new QueryWrapper();

// f就是QueryWrapper<Book>對象,該Lambda表達式必須返回布爾類型
// 因爲Wrapper沒有添加實體類對象,所以必須添加第一個方法參數Class<T> entityClass
// Lambda表達式篩選列是根據實體類的屬性名或列名進行篩選的,主鍵屬性無法過濾
// f.getProperty()獲取的是屬性名,f.getColumn()獲取的是列名
// SELECT book_id,book_name FROM book 
wrapper.select(Book.class,f->f.getProperty().contains("bookName"));



Book book=new Book();
book.setCategoryId(4);

// 調用帶參數Predicate<TableFieldInfo>必須聲明Wrapper的實參泛型
// 這裏把book實體對象放進了Wrapper中
QueryWrapper<Book> wrapper=new QueryWrapper(book);

// f就是QueryWrapper<Book>對象,該Lambda表達式必須返回布爾類型
// 因爲Wrapper添加實體類對象,所以不用再設置Class<T> entityClass參數
// Lambda表達式篩選列是根據實體類的屬性名或列名進行篩選的,主鍵屬性無法過濾
// f.getProperty()獲取的是屬性名,f.getColumn()獲取的是列名
// SELECT book_id,book_name FROM book WHERE category_id=? 
wrapper.select(f->f.getProperty().contains("bookName"));

4.5 UpdateWrapper

  • 特有方法
set(String column, Object val)  // 設置要修改的列和值
setSql(String sql)  // 設置更新sql語句中的set關鍵字的sql片段,注意防注入
lambda() // UpdateWrapper轉換爲LambdaUpdateWrapper
UpdateWrapper<Book> updateWrapper=new UpdateWrapper<>();
updateWrapper.set("book_name","UpdateWrapper書籍").set("category_id",8);
updateWrapper.eq("book_id",36);

//UPDATE book SET book_name=?,category_id=? WHERE (book_id = ?)
bookService.update(updateWrapper);

4.6 QueryChainWrapper與LambdaQueryChainWrapper

  • 獲取Wrapper方式
QueryChainWrapper qcWrapper=xxxService.query();
LambdaQueryChainWrapper lqcWrapper=xxxService.lambdaQuery();
  • 特有方法
T one()  //查詢返回一條記錄
List<T> list()  //查詢返回多條記錄
Integer count()  //查詢記錄數
E page(E page)  //分頁查詢
// SELECT * FROM book WHERE (category_id = ?) 
List<Book> bookList = bookService.query().eq("category_id",4).list();



Page<Book> page=new Page(1,2);  //分頁對象
// SELECT COUNT(1) FROM book WHERE (book_price > ? AND book_price < ?) 
// SELECT * FROM book WHERE (book_price > ? AND book_price < ?) LIMIT ?,? 
bookService.lambdaQuery().gt(Book::getBookPrice,50).lt(Book::getBookPrice,150).page(page);

long total = page.getTotal();  //總記錄數
long pages = page.getPages();  //總頁數
List<Book> bookList = page.getRecords();  //條件分頁後的查詢結果

4.7 UpdateChainWrapper與LambdaUpdateChainWrapper

  • 獲取Wrapper方法
UpdateChainWrapper ucWrapper=xxxService.update();
LambdaUpdateChainWrapper lucWrapper=xxxService.lambdaUpdate();
  • 特有方法
boolean update()  // 以條件構造器爲條件,必須調用set()方法設置需要修改的列
boolean update(T entity)  // 以條件構造器爲條件,以entity的非null屬性作爲需要更新的列
boolean remove()  // 以條件構造器爲條件,刪除多條記錄
// 第一個update()方法是獲取UpdateChainWrapper,第二個update()是執行update語句
// 因爲最後的update()沒有指定實體對象,所以必須調用set()方法設置需要修改列和值
// UPDATE book SET book_name=? WHERE (book_id = ?) 
bookService.update().set("book_name","書籍36已修改").eq("book_id",36).update();



// 使用實體對象指定需要修改列和值
Book book=new Book();
book.setBookName("書籍36Lambda修改");
// UPDATE book SET book_name=? WHERE (book_id = ?) 
bookService.lambdaUpdate().eq(Book::getBookId,36).update(book);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章