MyBatis Plus 增删改查 (三)

      • 1. CURD方法参数与返回值说明
        • 1.1 方法参数
        • 1.2 返回值
      • 2. BaseMapper CURD接口
        • 2.1 查询
        • 2.2 增加
        • 2.3 修改
        • 2.4 删除
      • 3. ServiceImpl CURD接口
        • 3.1 Get查询单条记录
        • 3.2 List查询多条记录
        • 3.3 Count查询记录数
        • 3.4 save新增数据
        • 3.5 update修改数据
        • 3.6 saveOrUpdate 根据主键值修改或新增
        • 3.7 remove 删除记录
        • 3.8 Page 分页查询
        • 3.9 Chain 链式方法
      • 4. 条件构造器
        • 4.1 条件合并
        • 4.2 AbstractWrapper的常用子类
        • 4.3 AbstractWrapper
        • 4.4 QueryWrapper
        • 4.5 UpdateWrapper
        • 4.6 QueryChainWrapper与LambdaQueryChainWrapper
        • 4.7 UpdateChainWrapper与LambdaUpdateChainWrapper

1. CURD方法参数与返回值说明

理解了方法参数与返回值,各个增删改查方法都是大同小异,都是各种重载方法。

1.1 方法参数

  • @Param(Constants.WRAPPER) Wrapper 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 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 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 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 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,因为结果集有多行记录
// List listObjs(Wrapper queryWrapper, Function mapper);
List<Serializable> list = bookService.listObjs(null, function);

1.2 返回值

  • int

    • 执行sql语句后受影响的行数
  • boolean

    • sql语句是否执行成功
  • List>

    • 每行记录为Map,列名为key,列值为value
  • List

    • 只返回第一列的数据
  • Collection

    • 跟List< T >一样
  • IPage

    • 封装了分页信息和分页查询记录
    • 分页操作需要配置分页插件,不能单纯调用方法,详情参考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,列名为key,列值为value
    List<Map<String, Object>> listMaps();
    
    // 根据Wrapper条件查询多条记录,返回List集合,每行记录为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类型
    IPage<T> page(IPage<T> page);
    
    // 条件分页查询,返回Page对象,封装的数据是List类型
    IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
    
    // 无条件分页查询,返回Page对象,封装的数据是List>类型
    IPage<Map<String, Object>> pageMaps(IPage<T> page);
    
    // 条件分页查询,返回Page对象,封装的数据是List>类型
    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,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 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 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方法参数的方法时,必须声明Wrapper时必须指定实际泛型,否则直接爆红编译错误
    QueryWrapper<Book> wrapper=new QueryWrapper();
    
    wrapper.gt("category_id",1);
    //w就是QueryWrapper对象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 predicate Lambda表达式,传递的参数是实体属性TableFieldInfo,Lambda返回值为true则表示该属性会作为查询列

    // 1个方法参数可以指定多列,多个参数最终会以逗号合并
    // SELECT book_name,book_price,book_date FROM book
    wrapper.select("book_name,book_price","book_date");
    
    
    
    // 调用带参数Predicate必须声明Wrapper的实参泛型
    QueryWrapper<Book> wrapper=new QueryWrapper();
    
    // f就是QueryWrapper对象,该Lambda表达式必须返回布尔类型
    // 因为Wrapper没有添加实体类对象,所以必须添加第一个方法参数Class 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必须声明Wrapper的实参泛型
    // 这里把book实体对象放进了Wrapper中
    QueryWrapper<Book> wrapper=new QueryWrapper(book);
    
    // f就是QueryWrapper对象,该Lambda表达式必须返回布尔类型
    // 因为Wrapper添加实体类对象,所以不用再设置Class 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);
    

    你可能感兴趣的:(#,MyBatis,Plus)