先上依赖
项目是springboot的,用的maven管理依赖
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
配置实体类和mapper
搞个实体类,默认实体类名和表名是对应的(忽略大小写),如果表名和类名不对应,那么就要使用@TableName("work")
public class Work implements Serializable {
注解来声明一下对应的表名
如果列名有特殊的,无法自动下划线转驼峰的,那么可以使用@TableField("company")
private String company;
对于id字段如果要设置成数据库自增那么需要声明一下@TableId(value = "id", type = IdType.AUTO)
private Long id;
有些字段在数据库中不存在,但是业务上又需要定义的时候@TableField(exist = false)
private String thisFieldisNotExistInDb;
IdType
的几种类型
然后写mapper
接口
接着启动类上面加mapperscan
扫描注解
开启mp的sql日志
mp默认是集成了logback日志的,所以只需要在yml里开启就行了
logging:
level:
root: info
com.fchan.hashmapstudy.dao: debug
配置是否开启驼峰和下划线互转
mybatis-plus:
configuration:
map-underscore-to-camel-case: true #开启驼峰和下划线互转
mp的通用service
先创建一个接口,继承mp
的IService
然后创建这个接口的实现类,这样就可以使用一些现成的方法了
方法可以参见官方文档里核心功能菜单下CRUD
接口
https://mp.baomidou.com/guide/crud-interface.html#save
mp使用PaginationInterceptor进行物理分页查询
我这边是springboot
项目,所以用注解引入PaginationInterceptor
拦截器
传统分页组件往往是
查count
:
select count(1) from (select * from user order by age desc, update_time desc)
查记录:
select * from user order by age desc, update_time desc limit 0,50
查count
时的order by
是完全可以去掉的!在复杂查询、大表、非索引字段排序等情况下查记录已经很慢了,查count
又要来一次!所以查count
显然希望优化为select count(1) from (select * from user)
但是也不是所有场景都可以优化的,比如带group by
的查询,所以MBP
源码如下实现,没有group by
且有order by
的语句,就把order by
去掉。
package com.fchan.hashmapstudy.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;
@Configuration
public class MybatisPageConfig {
@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;
}
}
在mapper
接口里定义一个分页查询方法,有多个参数的时候要给后面的condition
参数通过@Params
定义一个变量名,不然mybatis
识别不出来
在service
里也创建一个方法
在xml
里定义sql
语句分页查询数据
传入page
参数即可
//默认会查两次第一次查询count总数,第二次limit分页
//Page<Category> categoryIPage = new Page<>(1,3);
//isSearchCount传入false的话就不会count总数,只会查一次
Page<Category> categoryIPage = new Page<>(1,3, false);
Page<Category> categoryPage = categoryMapper.selectPage(categoryIPage, categoryLambdaQueryWrapper);
return objectMapper.writeValueAsString(categoryPage);
使用pagehelper
进行分页查询
先上依赖
我因为用了mybatisplus
所以依赖冲突了,在引入的pagehelper
依赖冲排除mybatis
的依赖,用mybatis
的直接引入即可
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.12</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</exclusion>
</exclusions>
</dependency>
在yml
中配置参数,pagehelper
不需要注册一个拦截器到spring
中
pagehelper:
helper-dialect: mysql #配置使用哪种数据库语言,不配置的话pageHelper也会自动检测
reasonable: true #配置分页参数合理化功能,默认是false
support-methods-arguments: true #支持通过Mapper接口参数来传递分页参数,默认值false
helper-dialect:
配置使用哪种数据库语言,不配置的话pageHelper
也会自动检测
reasonable:
配置分页参数合理化功能,默认是false
。
启用合理化时,如果pageNum<1会查询第一页,如果pageNum>总页数会查询最后一页
;
禁用合理化时,如果pageNum<1或pageNum>总页数会返回空数据
。
params:
为了支持startPage(Object params)
方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值; 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable
不配置映射的用默认值, 默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero
。
support-methods-arguments:
支持通过Mapper接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。
使用demo
紧跟PageHelper.startPage
后的第一个mapper
的查询方法会生效
//PageHelper.startPage(1,2);
//第三个count参数传入false的话就不会count总数,只会查一次,和mp自带的page一样
PageHelper.startPage(1,2, false);
PageInfo<Category> categoryPageInfo = new PageInfo<>(categoryMapper.selectAll());
mapper
直接使用lambdaWrapper
构造器查询
3种构造方式,我选的第三种,代码少
LambdaQueryWrapper<Category> lambda = new QueryWrapper<Category>().lambda();
//直接new LambdaQueryWrapper有深坑建议Wrappers.<Category>lambdaQuery()
LambdaQueryWrapper<Category> categoryLambdaQueryWrapper1 = new LambdaQueryWrapper<>();
LambdaQueryWrapper<Category> categoryLambdaQueryWrapper = Wrappers.<Category>lambdaQuery();
//like '%22%'
categoryLambdaQueryWrapper.like(Category::getCode,"33");
List<Category> categories1 = categoryMapper.selectList(categoryLambdaQueryWrapper);
复杂查询
// code like '33%' and ( name = 'after' and gmt_create is not null)
categoryLambdaQueryWrapper.likeRight(Category::getCode, "33")
.and(clqe -> clqe.eq(Category::getName,"after").isNotNull(Category::getGmtCreate));
List<Category> categories1 = categoryMapper.selectList(categoryLambdaQueryWrapper);
使用lambdaWrapper
更新
LambdaUpdateWrapper<Category> categoryLambdaUpdateWrapper = Wrappers.<Category>lambdaUpdate();
categoryLambdaUpdateWrapper.eq(Category::getCode, "333").and(q -> q.eq(Category::getName,"after")).set(Category::getName, "pambda");
int update = categoryMapper.update(null, categoryLambdaUpdateWrapper);
return String.valueOf(update);
User user = new User();
user.setId(5L);
user.setName("成老实");
user.setAge(23);
User whereUser = new User();
whereUser.setName("老成实");
whereUser.setAge(30);
whereUser.setId(5L);
/**
* 传入的实体中不为null的变量会出现在where中
* UPDATE user SET name=?, age=? WHERE id=? AND name=? AND age=? AND (name = ? AND age = ?)
*/
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>(whereUser);
updateWrapper.eq("name","老实成").eq("age",30);
int rows = userMapper.update(user,updateWrapper);
System.out.println("影响记录数:"+rows);
boolean update = new LambdaUpdateChainWrapper<User>(userMapper).eq(User::getName, "老实成")
.eq(User::getAge, 24).set(User::getAge, 20).update();
System.out.println("更新是否成功:"+update);