官方链接https://baomidou.com/pages/24112f/
基本使用
Springboot依赖配置
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3.4</version></dependency>
基本使用,以分页查询为例
配置
@Configuration@MapperScan("com.lff.dr.mapper")public class MybatisPlusConfig {// 最新版@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));return interceptor;}}
Model实体类
public class DictType {private Short id;private String name;private String value;private String intro;//getter and setter}
mapper层
import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.lff.dr.pojo.po.DictType;public interface DictTypeMapper extends BaseMapper<DictType> {}
service层
接口要继承IService并泛型要查询的对象
public interface DictTypeService extends IService<DictType> { //IService包含很多处理数据库的方法void list(DictTypeQuery query); //可以自定义方法}
Service实现层
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;import com.baomidou.mybatisplus.extension.plugins.pagination.Page;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import com.lff.dr.mapper.DictTypeMapper;import com.lff.dr.pojo.po.DictType;import com.lff.dr.pojo.query.DictTypeQuery;import com.lff.dr.service.DictTypeService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import org.springframework.util.StringUtils;@Service@Transactionalpublic class DictTypeServiceImpl extends ServiceImpl<DictTypeMapper,DictType> implements DictTypeService {@Autowiredprivate DictTypeMapper dictTypeMapper;public void list(DictTypeQuery query) {//设置查询条件LambdaQueryWrapper<DictType> wrapper = new LambdaQueryWrapper<>();if (!StringUtils.isEmpty(query.getKeyWord())){ //判断条件是否为空wrapper.like(DictType::getName,query.getKeyWord()).or().like(DictType::getIntro,query.getKeyWord());}//分页查询对象Page<DictType> page = new Page<>(query.getPage(),query.getSize());//执行查询page = dictTypeMapper.selectPage(page,wrapper);//保存查询的总页数query.setTotal(page.getTotal());//保存查询的结果集query.setData(page.getRecords());//保存当前页数据query.setCurrent(page.getCurrent());}}
Controller层
@Controllerpublic class DictTypeController {@Autowiredprivate DictTypeService dictTypeService;@RequestMapping("/dictType")public String fetchDictType(DictTypeQuery query,Model model){dictTypeService.list(query);model.addAttribute("query",query);return "list";}}
自定义分页方法
我们可以在Dao层也就是mapper里面自定义分页方法
public interface XxxMapper extends BaseMapper<T> {}
如果自定义的方法想分页查询,只需模仿官方的写法即可,官方的示例如下:
/*** 根据 entity 条件,查询全部记录(并翻页)** @param page 分页查询条件(可以为 RowBounds.DEFAULT)* @param queryWrapper 实体对象封装操作类(可以为 null)*/<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方法返回查询条件。
/*** 获取自定义SQL 简化自定义XML复杂情况* <p>* 使用方法: `select xxx from table` + ${ew.customSqlSegment}* <p>* 注意事项:* 1. 逻辑删除需要自己拼接条件 (之前自定义也同样)* 2. 不支持wrapper中附带实体的情况 (wrapper自带实体会更麻烦)* 3. 用法 ${ew.customSqlSegment} (不需要where标签包裹,切记!)* 4. ew是wrapper定义别名,不能使用其他的替换*/public String getCustomSqlSegment() {MergeSegments expression = getExpression();if (Objects.nonNull(expression)) {NormalSegmentList normal = expression.getNormal();String sqlSegment = getSqlSegment();if (StringUtils.isNotBlank(sqlSegment)) {if (normal.isEmpty()) {return sqlSegment;} else {return Constants.WHERE + StringPool.SPACE + sqlSegment;}}}return StringPool.EMPTY;}
�示例
Page selectPagesVo(Page page, @Param(Constants.WRAPPER) Wrapper<具体泛型的pojo对象> queryWrapper);
条件包装括号
使用nested函数可以把条件加()好,官方链接
QueryWrapper<ExamPlaceCourseVo> queryWrapper = new QueryWrapper<>();queryWrapper.nested(w->{w.like("name","张三").or().lt("age",18);});
遇到的问题:
问题1
如果使用LambdaQueryWrapper作为条件,里面又使用了方法的引用比如User::getName就会报错误
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.like(User::getName,"匹配的内容");baseMapper.selectPagesVo(new Page(1,20),queryWrapper);
报错信息
can not find lambda cache for this entity [com.lff.dr.pojo.vo.User]
原因是:在泛型LambdaQueryWrapper
public interface DictTypeMapper extends BaseMapper<DictType> {}
解决方法:
解决方法1:使用QueryWrapper并且不使用方法引用
解决方法2:mybatis-plus可以单独为一个类添加lambda cache,这需要手动配置,因为只需配置一次可以在InitializingBean方法里面配置
@Configuration@MapperScan("com.lff.dr.mapper")public class MybatisPlusConfig implements InitializingBean {// 最新版@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));return interceptor;}@Overridepublic void afterPropertiesSet() throws Exception {//实体类添加lambda cache,固定写法MapperBuilderAssistant assistant = new MapperBuilderAssistant(new MybatisConfiguration(), "");//添加具体的实体类TableInfoHelper.initTableInfo(assistant, User.class);TableInfoHelper.initTableInfo(assistant, xxx.class);}}
问题2
报类似如下信息
Column 'name' in where clause is ambiguous //name为表里面的字段
这一般是在多表关联查询时,name字段在关联表、多个表中都有这个字段引起的,比如SQL语句这样写
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.like(User::getName,"匹配的内容"); //User::getName会直接转成namebaseMapper.selectPagesVo(new Page(1,20),queryWrapper);
对应的XML语句
<select id="selectXXX"resultMap="hahha">select name,xxxfrom table_name1 join table_name2 on table_name1.id = table_name2.id${ew.customSqlSegment}</select>
在${ew.customSqlSegment}生成的where条件中name字段在table_name1表、table_name2表中都有name字段引起的。
解决方法:
显示指定name字段是哪个表里面的,是table_name1的还是table_name2的。不要使用LambdaQueryWrapper改为使用QueryWrapper。
QueryWrapper<Entity> queryWrapper = new QueryWrapper<>();queryWrapper.like("table_name1.name","xxx");
�在做条件查询的时候,最后标明哪个字段是哪个表中的,写全一点。
