3.4.0之前的版本
pom.xml文件
com.baomidou mybatis-plus-boot-starter3.3.1.tmp com.github.pagehelper pagehelper5.1.11
配置文件
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisConfig {
@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;
}
}
使用
controller层
//分页
@PostMapping("page")
public R page(@RequestBody(required = false) UserVo userVo){
//当前页
//int page = query.getCurrent() == null ? 1 : query.getCurrent();
//每页的页数
//int pageSize = query.getSize() == null ? 10 : query.getSize();
//创建一个分页对象 一般post 都是使用一个类文件接受相对应的参数
Page objectPage = new Page<>(userVo.getPage(),userVo.getSize());
//构造查询条件
QueryWrapper objectQueryWrapper = new QueryWrapper<>();
//条件查询
//名称
String name = userVo.getUserName();
//开始名称
String startTime = userVo.getStartTime();
//结束名称
String endTime = userVo.getEndTime();
//部门
String deptName =userVo.getDeptName();
//判断是否为空不为空则拼接
if (!StringUtils.isEmpty(deptName )){
//根据部门名查询部门名称
Dept one = deptService.findOneByName(deptName);
//实体类不为空则把部门id传进去为空传null
if (one!=null){
//前面数据库字段后面传递的参数
objectQueryWrapper.eq("dept_id", one.getId());
}else {
objectQueryWrapper.eq("dept_id", null);
}
}
if (!StringUtils.isEmpty(name)){
objectQueryWrapper.eq("real_name", name);
}
if(!StringUtils.isEmpty(startTime)){
objectQueryWrapper.apply("UNIX_TIMESTAMP(time)>=UNIX_TIMESTAMP('" + startTime + "')");
}
if(!StringUtils.isEmpty(endTime)){
objectQueryWrapper.apply("UNIX_TIMESTAMP(time)<=UNIX_TIMESTAMP('" + endTime + "')");
}
//调用方法 使用分页
Page page = UserService.page(objectPage, objectQueryWrapper);
page.getRecords().forEach(tGridPunchRecordEntity -> {
tGridPunchRecordEntity.setName(tsUserService.findById(tGridPunchRecordEntity.getUserId()).getRealName());
}
);
long total = objectPage.getTotal(); //总记录数
// List records = objectPage.getRecords(); //集合
List records = page.getRecords();
return R.okPage(records,total);
}
service需要继承IService<实体类>
public interface UserService extends IService条件构造器{ }
QueryWrapper查询 QueryWrapper<实体类> queryWrapper = new QueryWrapper<>(); List时间段查询ids= new ArrayList<>(); queryWrapper.in("id",ids); // 可入参数组查询 queryWrapper.and(wrapper->wrapper.eq("数字库字段",入参数据)); //可进行嵌套子查询
// 查询开始时间
String startTime = "2022-04-19"; //yyyy-MM-dd HH:mm:ss
queryWrapper.apply("UNIX_TIMESTAMP(start_time)>=UNIX_TIMESTAMP('" + startTime + "')");
//queryWrapper.ge("start_time",startTime);
// 结束时间
String endTime = "2022-04-20"; //yyyy-MM-dd HH:mm:ss
queryWrapper.apply("UNIX_TIMESTAMP(end_time)<=UNIX_TIMESTAMP('" + endTime + "')");
//queryWrapper.le("end_time",endTime);
// 备注:存入数据库的时间格式,和查询时间格式必须统一
condition(动态组装查询条件)
查询名字中包含n,年龄大于10且小于20的用户,查询条件来源于用户输入,是可选的
@Test
public void test1() {
//定义查询条件,有可能为null(用户未输入)
String name = null;
Integer ageBegin = 10;
Integer ageEnd = 20;
QueryWrapper queryWrapper = new QueryWrapper<>();
if(StringUtils.isNotBlank(name)){
queryWrapper.like("name","n");
}
if(ageBegin != null){
queryWrapper.ge("age", ageBegin);
}
if(ageEnd != null){
queryWrapper.le("age", ageEnd);
}
List users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
使用带condition参数的重载方法构建查询条件,简化代码的编写
@Test
public void test1Condition() {
//定义查询条件,有可能为null(用户未输入)
String name = null;
Integer ageBegin = 10;
Integer ageEnd = 20;
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper
.like(StringUtils.isNotBlank(name), "name", "n")
.ge(ageBegin != null, "age", ageBegin)
.le(ageEnd != null, "age", ageEnd);
List users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
LambdaQueryWrapper
@Test
public void test2() {
//定义查询条件,有可能为null(用户未输入)
String name = null;
Integer ageBegin = 10;
Integer ageEnd = 20;
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper
//避免使用字符串表示字段,防止运行时错误
//User 是用户实体类
.like(StringUtils.isNotBlank(name), User::getName, "n")
.ge(ageBegin != null, User::getAge, ageBegin)
.le(ageEnd != null, User::getAge, ageEnd);
List users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
插件
mybatisplus分页查询
配置类
@Configuration
@MapperScan("com.lyh.mybatisplus.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
Controller层
@GetMapping("/list")
@ApiOperation(value = "按条件分页查询")
public R list(@ApiParam(value = "当前页码", required = true) Long current,
@ApiParam(value = "每页记录数", required = true) Long size,
@ApiParam("查询对象条件") XXXVO xxxVO) {
//分页参数
Page page = new Page<>(current, size);
//调用service层查询
IPage<实体类> pageMode = knowledgeDataService.selectPage(page, xxxVO);
//分页查询 获取返回数据
List<实体类> dataList = pageMode.getRecords();
//获取查询数据总记录数
long total = pageMode.getTotal();
HashMap
service层
public IPage<实体类> selectPage(Page<实体类> page, XXXVO xxxVO) {
QueryWrapper<实体类> queryWrapper = new QueryWrapper<>();
//中间判断 加查询条件
Page<实体类> selectPage = baseMapper.selectPage(page, queryWrapper);
return selectPage;
}
自定义的 mapper#method 使用分页
UserMapper.java中定义接口方法
IPageselectPageByPage(Page> page, Integer age);
自定义UserMapper.java.xml
乐观锁 添加配置@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
在实体类的字段上加上@Version注解
@Version private Integer version;说明
**例子:**假设两个同时执行数据更新操作,会造成只有一个执行成功,另一个会被覆盖。
说明:
支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
整数类型下 newVersion = oldVersion + 1
newVersion 会回写到 entity 中
仅支持 updateById(id) 与 update(entity, wrapper) 方法
在 update(entity, wrapper) 方法下, wrapper 不能复用!!!
@TableName
@TableName(value = "t_user") //对应数据库中表的名字
public class User {
@TableId
@TableId(value = "uid") //映射数据表中的列名
private String id;
@TableField(可配置自动填充时间)
@TableField(value = "name") //映射数据表中的列名
private String name;
//自动填充表数据:创建时间、更新时间
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
// 注意:当对象的id被明确赋值时,不会使用雪花算法
@TableId(type = IdType.ASSIGN_ID) //雪花算法策略生成数据id
private Long id;
@TableId(type = IdType.AUTO) //使用数据库的自增策略
private Long id;
自动填充时间的处理类MyMetaObjectHandler.java
实现元对象处理器接口 -> 创建handler包,创建MyMetaObjectHandler类
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
@TableLogic逻辑删除
物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
使用场景:可以进行数据恢复
数据库中创建逻辑删除状态列
实体类中添加逻辑删除属性
@TableLogic @TableField(value = "is_deleted") private Integer deleted;
mybatis-plus时间范围查询的3种方式
实体类字段设置
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty("开始时间")
@TableField(exist = false)
private Date startTime;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty("截止时间")
@TableField(exist = false)
private Date endTime;
或者
@ApiModelProperty("开始时间")
@TableField(exist = false)
private Date startTime;
@ApiModelProperty("截止时间")
@TableField(exist = false)
private Date endTime;
数据库的create_time字段类型为datetime
第一种:
使用框架提供的查询方法
QueryWrapperqueryWrapper = Condition.getQueryWrapper(goods) .ge(Func.isNotEmpty(goods.getStartTime()),"create_time",goods.getStartTime()) .le(Func.isNotEmpty(goods.getEndTime()),"create_time",goods.getEndTime()); IPage pages = goodsService.page(Condition.getPage(query), queryWrapper);
第二种:
适用于自定义的查询方法
and o.create_time >= #{order.startTime} and o.create_time <= #{order.endTime}
第三种:
lambda方法构造查询方法
QueryWrapperqueryWrapper = new QueryWrapper<>(); LambdaQueryWrapper lambdaQueryWrapper = queryWrapper.lambda().ge(Func.isNotEmpty(goods.getStartTime()),Goods::getCreateTime, goods.getStartTime()); ambdaQueryWrapper = lambdaQueryWrapper.le(Func.isNotEmpty(goods.getEndTime()),Goods::getCreateTime, goods.getEndTime()); IPage pages = goodsService.page(Condition.getPage(query), lambdaQueryWrapper);
3.4.0之后的版本
com.baomidou mybatis-plus-boot-starter3.4.3.1
我是用的是3.4.3.1版本的依赖,倘若你想使用其他版本的依赖,你也可以自行去Maven仓库查找。
仓库地址:https://mvnrepository.com/artifact/com.baomidou/mybatis-plus
分页插件
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.classfee.chen.Mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
注意:
我们要将mybatisPlusInterceptor 这个方法注册到Bean里面,不然我们的插件就会失效。
使用@MapperScan这个注解,让系统扫描我们的Mapper类。注意一定要指定正确的Mapper地址。
在类方法上上面使用注解:@Configuration表面这是一个config类。
到这里我们的分页插件也就导入完成了,然后我们就需要去应用了。
语法总结
| 方法名 | 说明 | 用法实例 | 等价SQL |
|---|---|---|---|
| allEq(Map | 全部等于 | map.put(“id”,“3”);map.put(“user_name”,“IT可乐”);allEq(map) | user_name = “IT可乐” AND id = 3 |
| eq(R column, Object val) | 等于 = | eq(“id”,“3”) | id = 3 |
| ne(R column, Object val) | 不等于 <> | ne(“id”, “3”) | id <> 3 |
| gt(R column, Object val) | 大于 > | gt(“user_age”,“18”)user_age > 18 | user_age > 18 |
| ge(R column, Object val) | 大于等于 >= | ge(“user_age”,“18”) | user_age >= 18 |
| lt(R column, Object val) | 小于 < | lt(“user_age”,“18”) | user_age < 18 |
| le(R column, Object val) | 小于等于 <= | le(“user_age”,“18”) | user_age <= 18 |
| between(R column, Object val1, Object val2) | BETWEEN 值1 AND 值2 | between(“user_age”,“18”,“25”) | user_age BETWEEN 18 AND 25 |
| notBetween(R column, Object val1, Object val2) | NOT BETWEEN 值1 AND 值2 | notBetween(“user_age”,“18”,“25”) | user_age NOT BETWEEN 18 AND 25 |
| like(R column, Object val) | LIKE ‘%值%’ | like(“user_name”,“可乐”) | like ‘%可乐%’ |
| notLike(R column, Object val) | NOT LIKE ‘%值%’ | notLike(“user_name”,“可乐”) | not like ‘%可乐%’ |
| likeLeft(R column, Object val) | LIKE ‘%值’ | likeLeft(“user_name”,“可乐”) | like ‘%可乐’ |
| likeRight(R column, Object val) | LIKE ‘值%’ | likeRight(“user_name”,“可乐”) | like ‘可乐%’ |
| isNull(R column) | 字段 IS NULL | isNull(“user_name”) | user_name IS NULL |
| isNotNull(R column) | 字段 IS NOT NULL | isNotNull(“user_name”) | user_name IS NOT NULL |
| in(R column, Collection> value) | 字段 IN (value.get(0), value.get(1), …) | in(“user_age”,{1,2,3}) | user_age IN (?,?,?) |
| notIn(R column, Collection> value) | 字段 NOT IN (value.get(0), value.get(1), …) | notIn(“user_age”,{1,2,3}) | user_age NOT IN (?,?,?) |
| inSql(R column, String inValue) | 字段 IN ( sql语句 ) | inSql(“id”,“select id from user”) | id IN (select id from user) |
| notInSql(R column, String inValue) | 字段 NOT IN ( sql语句 ) | notInSql(“id”,“select id from user where id > 2”) | id NOT IN (select id from user where id > 2 |
| groupBy(R… columns) | 分组:GROUP BY 字段, … | groupBy(“id”,“user_age”) | GROUP BY id,user_age |
| orderByAsc(R… columns) | 排序【升序】:ORDER BY 字段, … ASC | orderByAsc(“id”,“user_age”) | ORDER BY id ASC,user_age ASC |
| orderByDesc(R… columns) | 排序【降序】:ORDER BY 字段, … DESC | orderByDesc(“id”,“user_age”) | ORDER BY id DESC,user_age DESC |
| orderBy(boolean condition, boolean isAsc, R… columns) | ORDER BY 字段, … | orderBy(true,true,“id”,“user_age”) | ORDER BY id ASC,user_age ASC |
| having(String sqlHaving, Object… params) | HAVINg ( sql语句 ) | having(“sum(user_age)>{0}”,“25”) | HAVINg sum(user_age)>25 |
| or() | 拼接 OR | eq(“id”,1).or().eq(“user_age”,25) | id = 1 OR user_age = 25 |
| and(Consumerconsumer) | AND 嵌套 | and(i->i.eq(“id”,1).ne(“user_age”,18)) | id = 1 AND user_age <> 25 |
| nested(Consumerconsumer) | 正常嵌套 不带 AND 或者 OR | nested(i->i.eq(“id”,1).ne(“user_age”,18)) | id = 1 AND user_age <> 25 |
| apply(String applySql, Object… params) | 拼接 sql(不会有SQL注入风险) | apply(“user_age>{0}”,“25 or 1=1”) | user_age >‘25 or 1=1’ |
| last(String lastSql) | 拼接到 sql 的最后,多次调用以最后一次为准(有sql注入的风险) | last(“limit 1”) | limit 1 |
| exists(String existsSql) | 拼接 EXISTS ( sql语句 ) | exists(“select id from user where user_age = 1”) | EXISTS (select id from user where user_age = 1) |



