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);