官方链接https://baomidou.com/pages/24112f/

基本使用

Springboot依赖配置

  1. <dependency>
  2. <groupId>com.baomidou</groupId>
  3. <artifactId>mybatis-plus-boot-starter</artifactId>
  4. <version>3.4.3.4</version>
  5. </dependency>

基本使用,以分页查询为例

配置

  1. @Configuration
  2. @MapperScan("com.lff.dr.mapper")
  3. public class MybatisPlusConfig {
  4. // 最新版
  5. @Bean
  6. public MybatisPlusInterceptor mybatisPlusInterceptor() {
  7. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  8. interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
  9. return interceptor;
  10. }
  11. }

Model实体类

  1. public class DictType {
  2. private Short id;
  3. private String name;
  4. private String value;
  5. private String intro;
  6. //getter and setter
  7. }

mapper层

  1. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  2. import com.lff.dr.pojo.po.DictType;
  3. public interface DictTypeMapper extends BaseMapper<DictType> {
  4. }

service层

接口要继承IService并泛型要查询的对象

  1. public interface DictTypeService extends IService<DictType> { //IService包含很多处理数据库的方法
  2. void list(DictTypeQuery query); //可以自定义方法
  3. }

Service实现层

  1. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  2. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  3. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  4. import com.lff.dr.mapper.DictTypeMapper;
  5. import com.lff.dr.pojo.po.DictType;
  6. import com.lff.dr.pojo.query.DictTypeQuery;
  7. import com.lff.dr.service.DictTypeService;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.stereotype.Service;
  10. import org.springframework.transaction.annotation.Transactional;
  11. import org.springframework.util.StringUtils;
  12. @Service
  13. @Transactional
  14. public class DictTypeServiceImpl extends ServiceImpl<DictTypeMapper,DictType> implements DictTypeService {
  15. @Autowired
  16. private DictTypeMapper dictTypeMapper;
  17. public void list(DictTypeQuery query) {
  18. //设置查询条件
  19. LambdaQueryWrapper<DictType> wrapper = new LambdaQueryWrapper<>();
  20. if (!StringUtils.isEmpty(query.getKeyWord())){ //判断条件是否为空
  21. wrapper.like(DictType::getName,query.getKeyWord()).or()
  22. .like(DictType::getIntro,query.getKeyWord());
  23. }
  24. //分页查询对象
  25. Page<DictType> page = new Page<>(query.getPage(),query.getSize());
  26. //执行查询
  27. page = dictTypeMapper.selectPage(page,wrapper);
  28. //保存查询的总页数
  29. query.setTotal(page.getTotal());
  30. //保存查询的结果集
  31. query.setData(page.getRecords());
  32. //保存当前页数据
  33. query.setCurrent(page.getCurrent());
  34. }
  35. }

Controller层

  1. @Controller
  2. public class DictTypeController {
  3. @Autowired
  4. private DictTypeService dictTypeService;
  5. @RequestMapping("/dictType")
  6. public String fetchDictType(DictTypeQuery query,Model model){
  7. dictTypeService.list(query);
  8. model.addAttribute("query",query);
  9. return "list";
  10. }
  11. }

自定义分页方法

我们可以在Dao层也就是mapper里面自定义分页方法

  1. public interface XxxMapper extends BaseMapper<T> {
  2. }

如果自定义的方法想分页查询,只需模仿官方的写法即可,官方的示例如下:

  1. /**
  2. * 根据 entity 条件,查询全部记录(并翻页)
  3. *
  4. * @param page 分页查询条件(可以为 RowBounds.DEFAULT)
  5. * @param queryWrapper 实体对象封装操作类(可以为 null)
  6. */
  7. <P extends IPage<T>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

官方第一个参数是分页对象,返回值也是分页对象,查询条件加了 @Param(Constants.WRAPPER),Constants._WRAPPER就是常量字符串ew。也就是_queryWrapper起个参数名称叫ew。其实@Param()里面的参数名称可以随便写,但官方推荐使用ew。

自定义分页功能

在自定义方法中,如果第一个参数传的是Page类型的对象,返回类型也是Page类型的对象,mybatis-plus
�内部会做拦截,自动为我们加分页语句即limit语句

自定义查询条件(官方链接

如果也想自动加where语句的条件,需要如下2步:1.参数为Wrapper类型的参数,前面要加@Param(Constants.WRAPPER),官方推荐写法。 2.xml的SQL语句中最后加${ew.customSqlSegment}
Wrapper对象有个方法getCustomSqlSegment。${ew.customSqlSegment}就会调用getCustomSqlSegment方法返回查询条件。

  1. /**
  2. * 获取自定义SQL 简化自定义XML复杂情况
  3. * <p>
  4. * 使用方法: `select xxx from table` + ${ew.customSqlSegment}
  5. * <p>
  6. * 注意事项:
  7. * 1. 逻辑删除需要自己拼接条件 (之前自定义也同样)
  8. * 2. 不支持wrapper中附带实体的情况 (wrapper自带实体会更麻烦)
  9. * 3. 用法 ${ew.customSqlSegment} (不需要where标签包裹,切记!)
  10. * 4. ew是wrapper定义别名,不能使用其他的替换
  11. */
  12. public String getCustomSqlSegment() {
  13. MergeSegments expression = getExpression();
  14. if (Objects.nonNull(expression)) {
  15. NormalSegmentList normal = expression.getNormal();
  16. String sqlSegment = getSqlSegment();
  17. if (StringUtils.isNotBlank(sqlSegment)) {
  18. if (normal.isEmpty()) {
  19. return sqlSegment;
  20. } else {
  21. return Constants.WHERE + StringPool.SPACE + sqlSegment;
  22. }
  23. }
  24. }
  25. return StringPool.EMPTY;
  26. }

�示例

  1. Page selectPagesVo(Page page, @Param(Constants.WRAPPER) Wrapper<具体泛型的pojo对象> queryWrapper);

条件包装括号

使用nested函数可以把条件加()好,官方链接

  1. QueryWrapper<ExamPlaceCourseVo> queryWrapper = new QueryWrapper<>();
  2. queryWrapper.nested(w->{
  3. w.like("name","张三").or().lt("age",18);
  4. });

遇到的问题:

问题1

如果使用LambdaQueryWrapper作为条件,里面又使用了方法的引用比如User::getName就会报错误

  1. LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
  2. queryWrapper.like(User::getName,"匹配的内容");
  3. baseMapper.selectPagesVo(new Page(1,20),queryWrapper);

报错信息

  1. can not find lambda cache for this entity [com.lff.dr.pojo.vo.User]

原因是:在泛型LambdaQueryWrapper上出了问题,只有拥有lambda cache的实体类才能使用LambdaQueryWrapper。可以理解只有BaseMapper泛型的类才有lambda cache。如下面的DictType实体类就有lambda cache

  1. public interface DictTypeMapper extends BaseMapper<DictType> {
  2. }

解决方法:
解决方法1:使用QueryWrapper并且不使用方法引用
解决方法2:mybatis-plus可以单独为一个类添加lambda cache,这需要手动配置,因为只需配置一次可以在InitializingBean方法里面配置

  1. @Configuration
  2. @MapperScan("com.lff.dr.mapper")
  3. public class MybatisPlusConfig implements InitializingBean {
  4. // 最新版
  5. @Bean
  6. public MybatisPlusInterceptor mybatisPlusInterceptor() {
  7. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  8. interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
  9. return interceptor;
  10. }
  11. @Override
  12. public void afterPropertiesSet() throws Exception {
  13. //实体类添加lambda cache,固定写法
  14. MapperBuilderAssistant assistant = new MapperBuilderAssistant(new MybatisConfiguration(), "");
  15. //添加具体的实体类
  16. TableInfoHelper.initTableInfo(assistant, User.class);
  17. TableInfoHelper.initTableInfo(assistant, xxx.class);
  18. }
  19. }

问题2

报类似如下信息

  1. Column 'name' in where clause is ambiguous //name为表里面的字段

这一般是在多表关联查询时,name字段在关联表、多个表中都有这个字段引起的,比如SQL语句这样写

  1. LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
  2. queryWrapper.like(User::getName,"匹配的内容"); //User::getName会直接转成name
  3. baseMapper.selectPagesVo(new Page(1,20),queryWrapper);

对应的XML语句

  1. <select id="selectXXX"
  2. resultMap="hahha">
  3. select name,xxx
  4. from table_name1 join table_name2 on table_name1.id = table_name2.id
  5. ${ew.customSqlSegment}
  6. </select>

在${ew.customSqlSegment}生成的where条件中name字段在table_name1表、table_name2表中都有name字段引起的。
解决方法:
显示指定name字段是哪个表里面的,是table_name1的还是table_name2的。不要使用LambdaQueryWrapper改为使用QueryWrapper。

  1. QueryWrapper<Entity> queryWrapper = new QueryWrapper<>();
  2. queryWrapper.like("table_name1.name","xxx");

�在做条件查询的时候,最后标明哪个字段是哪个表中的,写全一点。