mybatis-plus使用小結
前言
今年开始使用mybatis-plus ORM 框架对数据库操作,相比之前使用mybatis,mp 确实能大大提高开发效率,最近刚完成一个小项目,记录一下近期使用。mp是国人写的,官网的资料也很全,基本参考官网的内容摸索就能快速上手使用。mybatis-plus官网
这里只给出要点代码参考.我这里使用的MP的版本是: 3.4.2
一、yaml配置
mybatis-plus的 配置官网参考:使用配置
# mybatis plus 设置
mybatis-plus:
type-aliases-package: com.zlv11.*.entity
mapper-locations: classpath:mapper/*.xml
configuration:
# 开启执行日志打印
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
# 是否控制台 print mybatis-plus 的 LOGO 这里关闭
banner: false
二、优雅的查询
Mapper层 继承 BaseMapper 即可获取到通用简单的 增删改查,但是没有批量增,和灵活的根据相应条件进行修改删除操作。因此要使用MP的厉害之处就需要使用 Service CRUD 接口。
下面展示了3中查询方式:从优雅的角度来看,个人偏向使用第二或三种,当然第一种在query条件复用的情况下也能节省代码。也可以指定查询字段剔除不需要的字段,例如表中含有 text或longtext等大字段,比较影响性能,不需要的情况下剔除能提高查询性能。最后2中查询是使用MySQL函数的方式,可以做指定字段忽略大小写查询
SELECT table_id,flow_no,sponsor,create_time FROM appro_flow_main WHERE (sponsor = 'zlv11' AND lower(table_id) LIKE '%staff%')
。
/**
* @author lvzb
* @date 2022/09/07 16:59
**/
@Slf4j
@SpringBootTest
class FlowMainMapperTest {
@Resource
private FlowMainManager flowMainManager;
@Test
void test1() {
// 单条查询 方式一
QueryWrapper<FlowMain> query = new QueryWrapper<>();
query.lambda().eq(FlowMain::getFlowNo, "123456").eq(FlowMain::getSponsor, "zlv11");
FlowMain main1 = flowMainManager.getOne(query);
// 单条查询 方式二
FlowMain main2 = flowMainManager.getOne(Wrappers.<FlowMain>lambdaQuery()
.eq(FlowMain::getFlowNo, "123456")
.eq(FlowMain::getSponsor, "zlv11"));
// 单条查询 方式三
FlowMain main3 = flowMainManager.lambdaQuery()
.eq(FlowMain::getFlowNo, "123456")
.eq(FlowMain::getSponsor, "zlv11")
.one();
// 批量查询,指定字段,不指定默认是全字段查询 apply是使用SQL的函数
List<FlowMain> flowMainList = flowMainManager.lambdaQuery()
.eq(FlowMain::getFlowNo, "123456")
.eq(FlowMain::getSponsor, "zlv11")
.apply(String.format("find_in_set('%s',approver)", "hlb"))
.select(FlowMain::getId, FlowMain::getFlowNo, FlowMain::getSponsor, FlowMain::getCreateTime)
.list();
String tableName = "STaFF";
// 大小写不敏感 查询
List<FlowMain> flowMains = flowMainManager.lambdaQuery()
.eq(FlowMain::getSponsor, "zlv11")
.apply(StringUtils.isNotBlank(tableName), "lower(table_id) LIKE '%" + tableName.toLowerCase() + "%'")
.select(FlowMain::getTableId,FlowMain::getFlowNo,FlowMain::getSponsor,FlowMain::getCreateTime)
.list();
flowMains.stream().forEach(System.out::println);
}
}
三、优雅的更新
mybatis-plus的更新操作也是很优雅,类似查询也有好几种方式。
- 其中第一种方式,条件可以复用,同时也可以配合MP的一些属性自动填充机制,例如更具阿里的开发规范,表需要含有更新时间字段,这种就可以使用字段自动填充的机制进行处理。
- 第二第三种方式比较优雅,没有条件复用的情况下建议使用,但是无法使用自动填充机制,然后需要注意末尾的 updata()。
- 第四种方式末尾是remove(), 则会进行删除操作,如果链中也有各种set(),set()不起作用,也不会报错。
@Test
void test2() {
// 更新方式一: 配合MP的一些属性自动填充机制
UpdateWrapper<FlowMain> updateWrapper = new UpdateWrapper<>();
updateWrapper.lambda().eq(FlowMain::getId, 1).eq(FlowMain::getFlowInstanceNo, "aaa");
FlowMain flowMain = FlowMain.builder().id(1).flowInstanceNo("aaa").updateTime(LocalDateTime.now()).build();
flowMainManager.update(flowMain, updateWrapper);
// 更新方式二: 无法使用自动填充机制
flowMainManager.update(Wrappers.<FlowMain>lambdaUpdate().eq(FlowMain::getId, 1).eq(FlowMain::getFlowInstanceNo, "aaa")
.set(FlowMain::getSponsor, "zlv11").set(FlowMain::getUpdateTime, LocalDateTime.now()));
// 更新方式三: 无法使用自动填充机制
flowMainManager.lambdaUpdate()
.eq(FlowMain::getId, 1)
.eq(FlowMain::getFlowInstanceNo, "aaa")
.set(FlowMain::getSponsor, "zlv11")
.set(FlowMain::getUpdateTime, LocalDateTime.now())
.update();
// 方式四 remove就是删除
flowMainManager.lambdaUpdate()
.eq(FlowMain::getId, 1)
.eq(FlowMain::getFlowInstanceNo, "aaa")
.set(FlowMain::getSponsor, "zlv11") // set虽然可以设置实际上执行时是不生效的,也不会报错
.remove();
}
四、自动填充功能
参考官网使用,需要在实体的字段上加上 @TableField 注解标识 是插入时填充还是插入更新时填充。然后在 自定义元对象处理器接口实现类中配置好即可
Entity
/**
*
* @author lvzb
* @date 2022/08/09 10:40
**/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("appro_flow_main")
public class FlowMain implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;
private String flowInstanceNo;
private String flowInstanceName;
private String flowNo;
private String approStatus;
private String submitInfo;
private String tableId;
private String sponsor;
private Integer initiDate;
@TableField(fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
}
自定义实现类 MyMetaObjectHandler
这里给所有的 createTime ,updateTime字段定义插入时填充 当前日期, 更新时 对updateTime字段填充 当前日期。注意这里配置的字段,只有在entity中使用了注解 @TableField 修饰后,然后对应的新增和修改才会生效。
/**
*
* @author lvzb
* @date 2022/08/20 21:28
**/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class);
this.strictInsertFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class);
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class);
}
}
五、分页查询
分页查询是很常见的
配置分页插件
这个要更具你使用版本来,官网版本要求:3.4.0 版本以上 是如下配置
@Configuration
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}
老版本是这种配置
@Configuration
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
查询
普通的查询
@Test
void test3() {
Page<FlowMain> page = new Page<>(1,10);
flowMainManager.lambdaQuery().eq(FlowMain::getFlowNo,"123456").page(page);
List<FlowMain> records = page.getRecords();
}
复杂分页查询,传入xml内,确保第一个参数是 Page即可,执行后,查询数据会放到传入的Page 对象的 records 属性中
/**
* @author lvzb
* @date 2022/08/09 19:01
**/
@Mapper
public interface FlowMainMapper extends BaseMapper<FlowMain> {
/**
* 待办获取 分页
*
* @param page 分页参数
* @param request 请求参数
* @return Page<ApproNodeModel>
*/
Page<ApproNodeModel> selectToDoPage(Page<ApproNodeModel> page,
@Param("request") ToDoRequest request);
/**
* 已办获取 分页
*
* @param page 分页参数
* @param request 请求参数
* @return Page<ApproNodeModel>
*/
Page<ApproNodeModel> selectDonePage(Page<ApproNodeModel> page,
@Param("request") DoneRequest request);
}
@Test
void test() {
String approver = "zlv11";
DoneRequest doneRequest = new DoneRequest();
doneRequest.setUserNo(approver);
Page<ApproNodeModel> page1 = new Page<>(1, 10);
flowMainMapper.selectDonePage(page1, doneRequest);
page1.getRecords().stream().forEach(System.out::println);
}
控制台打印如下内容
2022-11-18 15:12:38.299 WARN 87776 --- [ main] c.a.d.b.dao.mapper.FlowMainMapperTest : >>> 10