MyBatis-Plus分页查询以及⾃定义sql分页
⼀、引⾔
分页查询每个⼈程序猿⼏乎都使⽤过,但是有部分同学不懂什么是物理分页和逻辑分页。
物理分页:相当于执⾏了limit分页语句,返回部分数据。物理分页只返回部分数据占⽤内存⼩,能够获取数据库最新的状态,实施性⽐较强,⼀般适⽤于数据量⽐较⼤,数据更新⽐较频繁的场景。
逻辑分页:⼀次性把全部的数据取出来,通过程序进⾏筛选数据。如果数据量⼤的情况下会消耗⼤量的内存,由于逻辑分页只需要读取数据库⼀次,不能获取数据库最新状态,实施性⽐较差,适⽤于数据量⼩,数据稳定的场合。
那么MP中的物理分页怎么实现呢? 往下看往下看
⼆、配置
创建MybatisPlusConfig配置类,需要配置分页插件,⼩编使⽤的Spring boot配置⽅式。
@Configuration
public class MyBatisPlusConfig {
/**
* 分页插件
* @return
*/
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
}
三、具体分页实现
MP的BaseMapper提供了两种分页查询的⽅式,源码如下:
/**
* 根据 entity 条件,查询全部记录(并翻页)
分页查询插件* @param page 分页查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
IPage<T>selectPage(IPage<T> page,@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类
*/
IPage<Map<String, Object>>selectMapsPage(IPage<T> page,@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
可见两个分页⽅法参数都是⼀致的,只是返回参数略有不同,具体选择根据实际业务为准。
/**
* 分页查询
*/
@Test
public void selectByPage(){
QueryWrapper<User> wrapper =new QueryWrapper();
wrapper.like("name","⾬").lt("age",40);
Page<User> page =new Page<>(1,2);
//IPage<User> userIPage = userMapper.selectPage(page, wrapper);
IPage<Map<String, Object>> mapIPage = userMapper.selectMapsPage(page, wrapper);
System.out.println("总页数"+Pages());
System.out.println("总记录数"+Total());
List<Map<String, Object>> records = Records();
records.forEach(System.out::println);
}
以上分页查询执⾏sql如下,先是查询了⼀次总记录数,然后在查询的数据。
DEBUG==> Preparing: SELECT COUNT(1) FROM user WHERE name LIKE ? AND age <?
DEBUG==> Parameters:%⾬%(String),40(Integer)
TRACE<== Columns:COUNT(1)
TRACE<== Row:2
DEBUG==> Preparing: SELECT id,name,age,email,manager_id,create_time FROM user WHERE name LIKE ? AND age <? LIMIT ?,?
DEBUG==> Parameters:%⾬%(String),40(Integer),0(Long),2(Long)
TRACE<== Columns: id, name, age, email, manager_id, create_time
TRACE<== Row:2,张⾬琪,31, zjq@baomidou,1088248166370832385,2019-01-1409:15:15
TRACE<== Row:3,刘红⾬,31, lhm@baomidou,1088248166370832385,2019-01-1409:48:16
DEBUG<== Total:2
总页数1
总记录数2
现在我们有需求只要查询数据即可,不关⼼总记录数等,如果使⽤默认的⽅式就消耗不必要的性能。那么解决办法也是很简单的,只需要在创建page对象时传⼊第三个参数为false即可。
Page<User> page =new Page<>(1,2,false);
MP的Iservice也提供了分页⽅法
源码:
/**
* 翻页查询
*
* @param page 翻页对象
* @param queryWrapper 实体对象封装操作类 {@link ditions.query.QueryWrapper} */
default<E extends IPage<T>> E page(E page, Wrapper<T> queryWrapper){
return getBaseMapper().selectPage(page, queryWrapper);
}
/**
* ⽆条件翻页查询
*
* @param page 翻页对象
* @see Wrappers#emptyWrapper()
*/
default<E extends IPage<T>> E page(E page){
return page(page, ptyWrapper());
}
/**
* 翻页查询
*
* @param page 翻页对象
* @param queryWrapper 实体对象封装操作类 {@link ditions.query.QueryWrapper} */
default<E extends IPage<Map<String, Object>>> E pageMaps(E page, Wrapper<T> queryWrapper){
return getBaseMapper().selectMapsPage(page, queryWrapper);
}
/**
* ⽆条件翻页查询
*
* @param page 翻页对象
* @see Wrappers#emptyWrapper()
*/
default<E extends IPage<Map<String, Object>>> E pageMaps(E page){
return pageMaps(page, ptyWrapper());
}
例⼦:
@Override
public LayTableResult list(Integer page, Integer limit, SysLoginLog sysLoginLog){
LambdaQueryWrapper<SysLoginLog> queryWrapper =new LambdaQueryWrapper<>();
if(StringUtils.Account())){
queryWrapper.like(SysLoginLog::getAccount, Account());
}
if(null!= Status()){
queryWrapper.eq(SysLoginLog::getStatus, Status());
}
IPage<SysLoginLog> iPage =page(new Page<>(page,limit,false), queryWrapper);
return new LayTableResult<>(Total(), Records());
}
两者主要的区别:
BaseMapper 针对dao层的⽅法封装 CRUD
IService<M,T> 针对业务逻辑层的封装 需要指定Dao层类和对应的实体类是在BaseMapper基础上的加强
ServiceImpl 针对业务逻辑层的实现
两者提供的⽅法略有不同
对⽐这两个接⼝,操作都差不多,名字有⼀点点改变,⽐如 BaseMapper ⾥⾯叫 insert() 的⽅法,在 IService ⾥⾯叫save()。
IService是对BaseMapper的扩展 另外,IService 的默认实现sion.se
rvice.impl.ServiceImpl 就是调⽤
BaseMapper 来操作数据库,所以我猜 IService 是 Java 8 之前对 BaseMapper 所做的扩展,⽽ Java 8之后,因为有了
default ⽅法,ServiceImpl ⾥⾯的东西其实都可以移到 BaseMapper ⾥⾯了。
除此之外还有就是IService (使⽤@service)依赖于 Spring 容器,⽽ BaseMapper (使⽤@mapper)不依赖;BaseMapper可以继承并添加新的数据库操作,IService 要扩展的话还是得调⽤ Mapper,显得有些多此⼀举。
四、⾃定义sql分页查询
有时候查询的数据难免会出现多表连接查询,或者是⼀些复杂的sql语句,但是这些语句也是需要⽀持分页查询的,
先定义查询接⼝,第⼀个参数要是分页的参数,⼩编这⾥演⽰就写简单的sql。
步骤⼀:在mapper⽂件中,编写对应的分页查询接⼝。
步骤⼆:在xml中编写对应的sql语句,⼩编这⾥演⽰的 “${ew.customSqlSegment}”,这个是如果你想⾃定义的sql语句,也想使⽤wrapper查询条件构造器,则需要在mapper接⼝中添加参数,以及xml中也要有固定。
/**
* ⾃定义sql分页
* @param page
* @param queryWrapper 看这⾥看这⾥,如果⾃定义的⽅法中需要⽤到wrapper查询条件,需要这样写
* @return
*/
IPage<User>selectMyPage(IPage<User> page,@Param(Constants.WRAPPER) Wrapper<User> queryWrapper);
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-////DTD Mapper 3.0//EN""/dtd/mybatis-3-mapper.dtd">
<mapper namespace="ample.demo.mapper.UserMapper">
<select id="selectMyPage"resultType="del.User">
SELECT * FROM user ${ew.customSqlSegment}
</select>
</mapper>
/**
* ⾃定义sql分页查询
*/
@Test
public void selectByMyPage(){
QueryWrapper<User> wrapper =new QueryWrapper();
wrapper.like("name","⾬").lt("age",40);
Page<User> page =new Page<>(1,2);
IPage<User> mapIPage = userMapper.selectMyPage(page, wrapper);
System.out.println("总页数"+Pages());
System.out.println("总记录数"+Total());
List<User> records = Records();
records.forEach(System.out::println);
}
五、多表sql分页查询
sql如下: his_ipd_encounter、his_user 两张表
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-////DTD Mapper 3.0//EN""/dtd/mybatis-3-mapper.dtd"> <mapper namespace="ample.demo.mapper.UserMapper">
<select id="selectByHisName"resultType="java.lang.String">
alname from his_ipd_encounter e, his_user u where e.his_uid = u.his_uid
</select>
</mapper>
mapepr如下:需要传⼊分页的参数,返回的类型也需要是分页对象
public interface UserMapper extends MyMapper<User>{
/**
* 多表查询分页
* @param page
* @return
*/
IPage<String>selectByHisName(IPage<User> page);
}
测试如下:通过查看⽇志,执⾏的sql加了分页条件的。
@Test
public void select(){
// 创建分页参数
Page<User> page =new Page<>(1,2);
IPage<String> result = userMapper.selectByHisName(page);
// 获取数据
List<String> records = Records();
records.forEach(System.out::println);
System.out.println("总页数 = "+ Pages());
}
ARNWarn: Could not find @TableId in Class:HisUser.
INFOStarted UserMapperTest in 2.428 seconds (JVM running for2.959)
alname from his_ipd_encounter e, his_user u where e.his_uid = u.his_uid
DEBUG==> Preparing: SELECT COUNT(1) FROM his_ipd_encounter e, his_user u WHERE e.his_uid = u.his_uid DEBUG==> Parameters:
TRACE<== Columns:COUNT(1)
TRACE<== Row:117
DEBUG==> Preparing: alname from his_ipd_encounter e, his_user u where e.his_uid = u.his_uid LIMIT ?,? DEBUG==> Parameters:0(Long),2(Long)
TRACE<== Columns: realname
TRACE<== Row:胡伯云
TRACE<== Row:安元慧
DEBUG<== Total:2
Time:20 ms - ID:UserMapper.selectByHisName
Execute SQL:
PreparedStatementWrapper@61bcbcce
胡伯云
安元慧
总页数=59
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论