【MyBatisPlus】MyBatisPlus 增删改查 (三)

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;

// MybatisPlus配置类
@Configuration
//@MapperScan("com.mapper") //项目启动类如果配置了MapperScan,这里可以省略
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);
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值