Java使用MyBatis框架分页的5种方式

本文为大家分享了Java使用MyBatis框架分页的五种方式,供大家参考,具体内容如下

初始准备

1.创建分页对象类,方便模块间传值

//PageInfo.java
import lombok.Data;

@Data
public class PageInfo {

  private int pageNo;

  private int pageSize;

}

2.定义DAO层接口

import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface UserMapper {

  User selectByUser(User user);
  List<User> selectAll();
  List<User> selectByPageInfo(PageInfo info);
  List<User> selectByInterceptor(PageInfo info);

  List<User> selectByRowBounds(RowBounds rowBounds);

}

3.mapper中定义结果集合BaseResult

<resultMap id="BaseResult" type="cn.edu.yau.pojo.User">
    <id property="id" column="id" jdbcType="INTEGER"></id>
    <result property="username" column="username" jdbcType="VARCHAR"></result>
    <result property="password" column="password" jdbcType="VARCHAR"></result>
 </resultMap>

一、原始切分:最原始方法,不建议使用

1.mapper代码:查询所有数据

<select id="selectAll" resultMap="BaseResult">
  select * from tb_user
</select>

2.业务层代码:利用List的subList()方法对数据进行切片

public List<User> findByAll(PageInfo info) {
    List<User> users = userMapper.selectAll();
    return users.subList(info.getPageNo(), info.getPageSize());
  }

3.控制层代码

@RequestMapping(value = "/userlist_1", method = RequestMethod.GET)
@ResponseBody
  public Result findUserBySubList(PageInfo info) {
    List<User> users = userService.findByAll(info);
    if(users.size() == 0) {
      return ResultGenerator.genFailResult("未查找到用户");
    }
    return ResultGenerator.genSuccessResult(users);
  }

二、LIMIT关键字

1.mapper代码:利用limit关键字实现分页

<select id="selectByPageInfo" resultMap="BaseResult">
    select * from tb_user limit #{pageNo}, #{pageSize}
</select>

2.业务层直接调用

public List<User> findByPageInfo(PageInfo info) {
    return userMapper.selectByPageInfo(info);
  }

3.控制层直接调用

三、RowBounds实现分页

1.在DAO层定义好所要传输的分页信息,类型为RowBounds

2.mapper层:查询所有数据

3.业务层:将PageInfo信息封装成RowBounds,调用DAO层方法

public List<User> findByRowBounds(PageInfo info) {
    return userMapper.selectByRowBounds(new RowBounds(info.getPageNo(), info.getPageSize()));
  }

4.控制层直接调用

四、MyBatis的Interceptor实现:实现复杂,需要明白MyBatis的实现

1.创建Interceptor

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;

import java.sql.Connection;
import java.util.Properties;

/**
 * 利用MyBatis拦截器进行分页
 *
 * @Intercepts 说明是一个拦截器
 * @Signature 拦截器的签名
 * type 拦截的类型 四大对象之一( Executor,ResultSetHandler,ParameterHandler,StatementHandler)
 * method 拦截的方法
 * args 参数,高版本需要加个Integer.class参数,不然会报错
 *
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class DefinedPageInterceptor implements Interceptor {

  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    //获取StatementHandler,默认的是RoutingStatementHandler
    StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
    //获取StatementHandler的包装类
    MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
    //分隔代理对象
    while (metaObject.hasGetter("h")) {
      Object obj = metaObject.getValue("h");
      metaObject = SystemMetaObject.forObject(obj);
    }
    while (metaObject.hasGetter("target")) {
      Object obj = metaObject.getValue("target");
      metaObject = SystemMetaObject.forObject(obj);
    }
    //获取查看接口映射的相关信息
    MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
    String mapId = mappedStatement.getId();
    //拦截以ByInterceptor结尾的请求,统一实现分页
    if (mapId.matches(".+ByInterceptor$")) {
      System.out.println("LOG:已触发分页拦截器");
      //获取进行数据库操作时管理参数的Handler
      ParameterHandler parameterHandler = (ParameterHandler) metaObject.getValue("delegate.parameterHandler");
      //获取请求时的参数
      PageInfo info = (PageInfo) parameterHandler.getParameterObject();
      //获取原始SQL语句
      String originalSql = (String) metaObject.getValue("delegate.boundSql.sql");
      //构建分页功能的SQL语句
      String sql = originalSql.trim() + " limit " + info.getPageNo() + ", " + info.getPageSize();
      metaObject.setValue("delegate.boundSql.sql", sql);
    }
    //调用原对象方法,进入责任链下一级
    return invocation.proceed();
  }

  @Override
  public Object plugin(Object target) {
    //生成Object对象的动态代理对象
    return Plugin.wrap(target, this);
  }

  @Override
  public void setProperties(Properties properties) {
    //如果分页每页数量是统一的,可以在这里进行统一配置,也就无需再传入PageInfo信息了
  }
}

2.将Interceptor添加至MyBatisConfig中,这里采用JavaConfig的方式

@Bean
  public SqlSessionFactoryBean sqlSession() {
    SqlSessionFactoryBean sqlSession = new SqlSessionFactoryBean();
    sqlSession.setDataSource(dataSource());
    try {
      Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml");
      sqlSession.setMapperLocations(resources);
      //配置自定义的Interceptro作为MyBatis的Interceptor,完成分页操作
      DefinedPageInterceptor definedPageInterceptor = new DefinedPageInterceptor();
      sqlSession.setPlugins(new Interceptor[]{definedPageInterceptor});
      return sqlSession;
    } catch (IOException e) {
      e.printStackTrace();
    }
    return null;
  }

3.DAO层接口方法名需要和代码中自定义的".+ByInterceptor$"正则表达式相匹配,mapper的书写依然是查询所有数据

<select id="selectByInterceptor" resultMap="BaseResult">
    select * from tb_user
</select>

4.业务层直接调用

5.控制层直接调用

五、开源项目PageHelper实现:本质还是自己封装了个Interceptor

1.引入PageHelper的jar包

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.10</version>
</dependency>

2.配置PageInterceptor

public PageInterceptor initPageInterceptor(){
    PageInterceptor pageInterceptor = new PageInterceptor();
    Properties properties = new Properties();
    //设置数据库类型
    properties.setProperty("helperDialect", "mysql");
    //该参数默认为false
    //设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用
    //和startPage中的pageNum效果一样
    properties.setProperty("offsetAsPageNum", "true");
    //该参数默认为false
    //设置为true时,使用RowBounds分页会进行count查询
    properties.setProperty("rowBoundsWithCount", "true");
    pageInterceptor.setProperties(properties);
    return pageInterceptor;
  }

  @Bean
  public SqlSessionFactoryBean sqlSession() {
    SqlSessionFactoryBean sqlSession = new SqlSessionFactoryBean();
    sqlSession.setDataSource(dataSource());
    try {
      Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml");
      sqlSession.setMapperLocations(resources);
      //配置PageHelper作为MyBatis的Interceptor,完成分页操作
      PageInterceptor pageInterceptor = this.initPageInterceptor();
      //配置自定义的Interceptro作为MyBatis的Interceptor,完成分页操作
      DefinedPageInterceptor definedPageInterceptor = new DefinedPageInterceptor();
      sqlSession.setPlugins(new Interceptor[]{pageInterceptor, definedPageInterceptor});
      return sqlSession;
    } catch (IOException e) {
      e.printStackTrace();
    }
    return null;
  }

3.mapper依然是查询所有数据

4.为DAO层再封装一次方法

@Repository
public class PageHelperHandler {

  @Autowired
  private SqlSessionFactory sqlSessionFactory;

  public List<User> findByPageHelper(PageInfo info) {
    SqlSession session = sqlSessionFactory.openSession();
    PageHelper.startPage(info.getPageNo(), info.getPageSize());
    //写到要使用到的类名和方法名
    List<User> users = session.selectList("cn.edu.yau.mapper.UserMapper.selectAll");
    return users;
  }

}

6.业务层直接调用Handler

7.控制层直接调用

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java简单实现SpringMVC+MyBatis分页插件

    1.封装分页Page类 package com.framework.common.page.impl; import java.io.Serializable; import com.framework.common.page.IPage; /** * * * */ public abstract class BasePage implements IPage, Serializable { /** * */ private static final long serialVersionUID

  • Java的MyBatis框架中实现多表连接查询和查询结果分页

    实现多表联合查询 还是在david.mybatis.model包下面新建一个Website类,用来持久化数据之用,重写下相应toString()方法,方便测试程序之用. package david.mybatis.model; import java.text.SimpleDateFormat; import java.util.Date; public class Website { private int id; private String name; private int visito

  • Java使用MyBatis框架分页的5种方式

    本文为大家分享了Java使用MyBatis框架分页的五种方式,供大家参考,具体内容如下 初始准备 1.创建分页对象类,方便模块间传值 //PageInfo.java import lombok.Data; @Data public class PageInfo { private int pageNo; private int pageSize; } 2.定义DAO层接口 import org.apache.ibatis.session.RowBounds; import org.springf

  • Java项目开发中实现分页的三种方式总结

    目录 前言 使用 1.SpringDataJPA分页 2.MyBatis分页 3.Hutools工具类分页 总结 前言 Java项目开发中经常要用到分页功能,现在普遍使用SpringBoot进行快速开发,而数据层主要整合SpringDataJPA和MyBatis两种框架,这两种框架都提供了相应的分页工具,使用方式也很简单,可本人在工作中除此以外还用到第三种更方便灵活的分页方式,在这里一同分享给大家. 使用 主要分为SpringDataJPA分页.MyBatis分页.Hutools工具类分页几个部

  • 浅谈MyBatis执行SQL的两种方式

    目录 前言 准备接口和Mapper配置文件: 使用SqlSession 发送 SQL 使用 Mapper 接口发送 SQL 比较两种发送 SQL 方式 前言 本文介绍MyBatis执行SQL语句的2种方式:SqlSession和Mapper接口以及它们的区别. 准备接口和Mapper配置文件: 定义UserMapper接口: package cn.cvs.dao; import cn.cvs.pojo.User; import java.util.List; public interface U

  • MyBatis批量插入的三种方式比较总结

    前言 数据库使用的是SQLServer,JDK版本1.8,运行在SpringBoot环境下 对比3种可用的方式 反复执行单条插入语句 xml拼接sql 批处理执行 先说结论:少量插入请使用反复插入单条数据,方便.数量较多请使用批处理方式.(可以考虑以有需求的插入数据量 20条左右为界吧,在我的测试和数据库环境下耗时都是百毫秒级的,方便最重要). 无论何时都不用xml拼接sql的方式. 代码 拼接SQL的xml newId()是sqlserver生成UUID的函数,与本文内容无关 <insert

  • Java详解实现多线程的四种方式总结

    目录 前言 一.四种方式实现多线程 1.继承Thread类创建线程 2.实现Runnable接口创建线程 3.实现Callable接口 4.实现有返回结果的线程 二.多线程相关知识 1.Runnable 和 Callable 的区别 2.如何启动一个新线程.调用 start 和 run 方法的区别 3.线程相关的基本方法 4.wait()和 sleep()的区别 5.多线程原理 前言 Java多线程实现方式主要有四种: ① 继承Thread类.实现Runnable接口 ② 实现Callable接

  • Java 从网上下载文件的几种方式实例代码详解

    废话不多说了,直接给大家贴代码了,具体代码如下所示: package com.github.pandafang.tool; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.nio.chan

  • 详解Java中数组判断元素存在几种方式比较

    1. 通过将数组转换成List,然后使用List中的contains进行判断其是否存在 public static boolean useList(String[] arr,String containValue){ return Arrays.asList(arr).contains(containValue); } 需要注意的是Arrays.asList这个方法中转换的List并不是java.util.ArrayList而是java.util.Arrays.ArrayList,其中java.

  • Java创建和启动线程的两种方式实例分析

    本文实例讲述了Java创建和启动线程的两种方式.分享给大家供大家参考,具体如下: 方式1:继承Thread类 步骤: 1):定义一个类A继承于java.lang.Thread类. 2):在A类中覆盖Thread类中的run方法. 3):我们在run方法中编写需要执行的操作:run方法里的代码,线程执行体. 4):在main方法(线程)中,创建线程对象,并启动线程. (1)创建线程类对象: A类 a = new A类(); (2)调用线程对象的start方法: a.start();//启动一个线程

  • java List去掉重复元素的几种方式(小结)

    使用LinkedHashSet删除arraylist中的重复数据(有序) LinkedHashSet是在一个ArrayList删除重复数据的最佳方法.LinkedHashSet在内部完成两件事: 删除重复数据 保持添加到其中的数据的顺序 List<String> words= Arrays.asList("a","b","b","c","c","d"); HashSet<

  • java base64编码、解码的三种方式总结

    1.用法介绍 方式一:DatatypeConverter 说明:使用jdk自带的DatatypeConverter.java类实现,但是jdk版本必须>=1.6. import java.io.UnsupportedEncodingException; import javax.xml.bind.DatatypeConverter; 编码 /** * base64编码之方法一 * @explain DatatypeConverter.java实现 * @param str * 待编码字符串 *

随机推荐