mybatis 实现查询默认添加分页

前言

        分页查询在日常开发中无法避免,但每次sql编写时,mybatis 中使用limit,oracle中使用rownum分页,业务场景少的情况下,可以接受.但是随着业务增加每次相同的功能做重复开发又不是那么方便,那么我们有什么方案去解决开发中出现的分页问题呢?

一、PageHelper 框架分页

首先我们看下pageHelper框架的分页核心类PageInterceptor 同样是实现了mybatis的Interceptor

                

二、自定义实现mybatis 插件 Interceptor (与pageHelper类似)

  •    当涉及系统中的查询语句,参数为RowBounds时,查询语句会默认根据RowBounds分页

package com.cloud.common;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.builder.StaticSqlSource;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Properties;

/**
 * @author haizhuangbu
 * @date 2022/6/5 18:25
 * @mark MybatisIntercepter mybatis 拦截器
 */
@Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
@Slf4j
public class MybatisInterceptor implements Interceptor {

    private Logger logger = LoggerFactory.getLogger(MybatisInterceptor.class);

    private final Integer MAPPED_STATEMENT_INDEX = 0;

    private final Integer PARAM = 1;

    // 默认分页
    private final Integer ROW_BOUNDS_INDEX = 2;


    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        logger.info("分页拦截器");
        // 1. 方法获取参数
        Object[] args = invocation.getArgs();
        // 分页器
        RowBounds rowBounds = (RowBounds) args[ROW_BOUNDS_INDEX];
        // 检查是否为默认分页
        if (rowBounds == RowBounds.DEFAULT) {
            return invocation.proceed();
        }
        // 设置为默认
        args[ROW_BOUNDS_INDEX] = RowBounds.DEFAULT;
        // 执行器
        MappedStatement mappedStatements = (MappedStatement) args[MAPPED_STATEMENT_INDEX];

        // 获取执行sql
        BoundSql boundSql = mappedStatements.getBoundSql(PARAM);

        String sql = boundSql.getSql();

        // 获取数据库类型
        String databaseProductName = mappedStatements.getConfiguration().getEnvironment().getDataSource().getConnection().getMetaData().getDatabaseProductName();

        // mysql 的 分页处理
        if ("MYSQL".equalsIgnoreCase(databaseProductName)) {
            sql = mysql(sql, rowBounds);
        }

        // oracle 的分页处理
        if ("ORACLE".equalsIgnoreCase(databaseProductName)) {
            sql = oracle(sql, rowBounds);
        }
        logger.info("sql:{}", sql);
        StaticSqlSource staticSqlSource = new StaticSqlSource(mappedStatements.getConfiguration(), sql, boundSql.getParameterMappings());
        // 通过反射设置MapperStatment 的sqlSource字段
        Field field = MappedStatement.class.getDeclaredField("sqlSource");
        field.setAccessible(true);
        field.set(mappedStatements, staticSqlSource);

        return invocation.proceed();
    }

    private String oracle(String sql, RowBounds rowBounds) {


        // 为查询语句给到别名
        sql = "select * from (select t1.*, rownum rn from (" + sql +
                ") t1 ) t2 where rn > " + (rowBounds.getOffset() - 1) * rowBounds.getLimit() + " and rn <= " + rowBounds.getOffset() * rowBounds.getLimit();
        return sql;

    }

    private String mysql(String sql, RowBounds rowBounds) {
        // 页数
        int limit = rowBounds.getLimit();

        // 页码
        int offset = rowBounds.getOffset();

        String format = String.format("LIMIT %d,%d", offset, limit);

        if (sql.contains(format)) {
//            sql = sql.replaceAll("select", "SELECT COUNT(1) total,");
            sql = sql.replaceAll(format, "");
        }

        sql += " " + format;
        return sql;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        Interceptor.super.setProperties(properties);
    }


}
  • 将自定义插件交给spring


    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return new ConfigurationCustomizer() {
            @Override
            public void customize(Configuration configuration) {
                configuration.addInterceptor(new MybatisInterceptor());
            }
        };
    }

  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot应用程序中使用MyBatis进行分页,可以通过以下步骤完成: 1. 引入MyBatisMyBatis分页插件依赖。例如,可以在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.3.1</version> </dependency> ``` 2. 在MyBatis配置文件中配置分页插件。例如,在application.properties中添加以下配置: ``` mybatis.mapper-locations=classpath:mapper/*.xml pagehelper.helper-dialect=mysql pagehelper.reasonable=true pagehelper.support-methods-arguments=true pagehelper.params=count=countSql ``` 3. 在Mapper接口中添加分页查询方法。例如: ``` public interface UserMapper { List<User> getUsersByPage(@Param("start") int start, @Param("size") int size); } ``` 4. 在Mapper XML文件中实现分页查询。例如: ``` <select id="getUsersByPage" resultType="User"> SELECT * FROM user LIMIT #{start}, #{size} </select> ``` 5. 在Service层中调用Mapper接口的分页查询方法,并传入起始位置和每页大小。例如: ``` @Service public class UserService { @Autowired private UserMapper userMapper; public List<User> getUsersByPage(int pageNum, int pageSize) { int start = (pageNum - 1) * pageSize; return userMapper.getUsersByPage(start, pageSize); } } ``` 以上就是在Spring Boot应用程序中使用MyBatis进行分页的基本步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值