`

mybatis简单的分页插件

 
阅读更多

mybatis的SqlSession可以直接通过以下接口来进行分页查询:

<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);

 不过该查询是基于对查询结果去子集的方式。该方法效率较低(如果只查询一条数据服务器需要返回所有满足条件的数据)。

 

实现思路:用mybatis插件拦截StatementHandler的prepare方法,修改Sql语句,添加分页查询语句。至于分页中的总页数查询,另执行一条select count(*)查询语句。实现较简单。

StatementHandler 的执行过程简介:

在Executor中通过下面代码创建StatementHandler

 

StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);

 configuration是mybatis的全局配置文件,其newStatementHandler创建过程如下:

  public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
    statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
    return statementHandler;
  }

 RoutingStatementHandler可以看作是非法语句处理器,具体的操作还是要委托给具体的BaseStatementHandler。interceptorChain.pluginAll用于将所有配置的myabtis插件类应用到这个接口上面。interceptorChain是一个拦截器链(职责链模式)

 

  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }

 interceptors保存着配置mybatis的所有拦截器,分别调用拦截器对目标进行代理。也就是生成目标类的代理。例如拦截器Incet

package cn.liuyao.mybatis.test;

import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;

@Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args = {java.sql.Connection.class})})
public class Incet implements Interceptor{

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		return invocation.proceed();
	}

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

	@Override
	public void setProperties(Properties properties) {

	}
}

 拦截器的plugin方法调用Plugin的wrap对目标对象包装代理。

  public static Object wrap(Object target, Interceptor interceptor) {
    Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
    Class<?> type = target.getClass();
    Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
    if (interfaces.length > 0) {
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
  }

 wrap返回目标对象的代理,这样在执行特定接口的特定方法时候,能够增加自己的一些代码,类似于spring的aop功能。

Object intercept(Invocation invocation)

intercept编写额外的代码。实现自己的分页逻辑。

 由于mybatis的语句执行,最终都由StatementHandler来完成,故只要拦截该接口的prepare方法,并修改boundSql与rowBound既可以达到修改Sql与添加分页信息的效果。

Page类:

 

package com.ccq.framework.lang;

import java.io.Serializable;

public class Page implements Serializable{

	private static final long serialVersionUID = 9000151198919642793L;

	private int pages;
	private int pageNum;
	private int pageSize;
	
	public Page() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Page(int pages, int pageNum, int pageSize) {
		super();
		this.pages = pages;
		this.pageNum = pageNum;
		this.pageSize = pageSize;
	}
	public int getPages() {
		return pages;
	}
	public void setPages(int pages) {
		this.pages = pages;
	}
	public int getPageNum() {
		return pageNum;
	}
	public void setPageNum(int pageNum) {
		this.pageNum = pageNum;
	}
	public int getPageSize() {
		return pageSize;
	}
	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}
}
 page类用于保存分页信息:当前页,页大小,所有页数。

 

pagePlugin:

package com.ccq.framework.plugin;

import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args = {java.sql.Connection.class})})
public class MyPagePlugin implements Interceptor{

	private Dialect dialect;
	
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		
		Logger log = LoggerFactory.getLogger(MyPagePlugin.class);
		
		StatementHandler hander = (StatementHandler) invocation.getTarget();
		//对handler进行包装可以获取其私有属性
		MetaObject meta = MetaObject.forObject(hander, new DefaultObjectFactory(), 
				new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
		RowBounds rowBound = (RowBounds) meta.getValue("delegate.rowBounds");//获取分页信息
		
		if(rowBound.equals(RowBounds.DEFAULT)) {
			
			//未指定分页命令
			return invocation.proceed();
		}
		BoundSql boundSql = (BoundSql) meta.getValue("delegate.boundSql");//获取sql语句
		
		if(dialect == null) {
			
			log.debug("not assigned dialect,use mysql default");
			dialect = new MysqlDialect();
		}
		
		String buildSql = dialect.builderSql(boundSql.getSql(), rowBound.getOffset(), rowBound.getLimit());
		MetaObject boundSqlMeta = MetaObject.forObject(boundSql, new DefaultObjectFactory(), 
				new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
		
		boundSqlMeta.setValue("sql", buildSql);
		
		meta.setValue("delegate.rowBounds", RowBound.DEFAULT);//回复默认的分页信息
		return invocation.proceed();
	}

	//生成目标对象的代理
	@Override
	public Object plugin(Object target) {
		if(target instanceof StatementHandler) {
			return Plugin.wrap(target, this);
		}else {
			return target;
		}
	}

	@Override
	public void setProperties(Properties properties) {
		if(properties.getProperty("dialect").equals("mysql")) {
			dialect = new MysqlDialect();
		}else if(properties.getProperty("dialect").equals("oracle")) {
			
			//TODO
		}
	}

}
 buildSql:

 

package com.ccq.framework.plugin;

import com.ccq.framework.exception.AppException;

public class MysqlDialect extends Dialect{

	@Override
	public String builderSql(String rawSql,int OFFSET,int LIMIT) {
		
		if(rawSql.endsWith(";")) {
			
			throw new AppException("Bad sql: grammer error on ; with limit");
		}
		
		StringBuffer sb = new StringBuffer(rawSql);
		//SELECT * FROM table LIMIT [offset,] rows
		sb.append(String.format(" limit %s,%s",new Object[]{OFFSET,LIMIT}));
		return sb.toString();
	}
}

 只针对mysql的sql语句。

 

测试:采用了的mybatis的通用单表CRUD工具,后面给链接。

 
分享到:
评论

相关推荐

    06实现mybatis分页插件demo

    06实现mybatis分页插件demo06实现mybatis分页插件demo06实现mybatis分页插件demo06实现mybatis分页插件demo06实现mybatis分页插件demo06实现mybatis分页插件demo06实现mybatis分页插件demo06实现mybatis分页插件demo...

    mybatis物理分页插件

    而“mybatis物理分页插件”是针对MyBatis设计的一个扩展,用于解决在大数据量查询时的性能问题,通过实现物理分页来避免内存溢出。 物理分页是指在数据库层面进行分页,相比于逻辑分页(在应用层进行数据截取),...

    Mybatis通用分页插件

    Mybatis通用分页插件是Java开发中广泛使用的ORM(对象关系映射)框架扩展,主要针对Mybatis进行优化,提供了高效便捷的分页功能。这个插件的目的是简化在数据库查询时的分页操作,使得开发者能够更专注于业务逻辑,...

    mybatis分页插件代码

    【标题】"mybatis分页插件代码"主要涉及到MyBatis框架中的一种增强功能——分页插件的使用。MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。在处理大数据量时,分页查询是必不可少的优化...

    Spring Boot集成MyBatis与分页插件

    本教程将详细讲解如何在Spring Boot项目中集成MyBatis,并利用分页插件实现高效的数据分页。 首先,我们需要在Spring Boot项目中引入MyBatis依赖。在`pom.xml`文件中添加以下Maven依赖: ```xml &lt;groupId&gt;org....

    mybatis的分页插件

    MyBatis 分页插件是针对 MyBatis 框架设计的一款强大的辅助工具,它极大地简化了在数据库查询时的分页操作。在没有分页插件的情况下,开发者需要手动编写分页相关的 SQL 语句,这既繁琐又容易出错。而 PageHelper ...

    MyBatis高级应用:实现自定义分页插件

    本文将详细介绍如何在 MyBatis 中实现自定义分页插件。 自定义分页插件提供了一种灵活且高效的方式来实现 MyBatis 的分页查询。通过实现 Interceptor 接口并注册插件,我们可以根据不同的业务需求和数据库特性来定制...

    mybatis平台包 集成分页插件

    mybatis集成了分页的插件,采用springmvc+spring+mybatis或者springboot+mybatis的时候可以无缝对接使用

    mybatis分页插件支持查询

    mybatis分页插件支持查询~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    mybatis 通用分页插件和批量操作插件

    NULL 博文链接:https://hzs0502030128.iteye.com/blog/2254585

    Jsp+Servlet+MyBatis完成分页查询

    在本文中,我们将深入探讨如何使用JSP、Servlet和MyBatis这三种技术来实现一个分页查询的功能。这是一个常见的需求,在许多Web应用程序中,为了提高用户体验,通常需要将大量数据分批次展示,而不是一次性加载所有...

    mybatis分页插件的使用

    ### Mybatis分页插件详解 #### 一、概述 在使用Mybatis处理大量数据时,分页查询是一项常见的需求。传统的做法是在SQL语句中手动加入`LIMIT`和`OFFSET`来实现分页功能,这种方法不仅繁琐而且容易出错。针对这一...

    MyBatis分页插件.rar

    MyBatis分页插件是数据库操作中常用的一种工具,它可以帮助开发者在使用MyBatis框架进行数据查询时实现高效且便捷的分页功能。在Java Web开发中,当需要处理大量的数据时,分页显示不仅可以提高用户体验,也能减轻...

    myBatis自动分页插件PageHelper5.0

    myBatis自动分页插件PageHelper5.0,支持自动分页,很方便,内含两个java包,分别是:PageHelper5.0.1.jar;jsqlparser-0.9.4.jar(PageHelper 4.1.0 及以后版本需要此包支持)

    springboot项目(四)添加mybatis分页插件

    在本篇中,我们将深入探讨如何在Spring Boot项目中集成MyBatis分页插件,以便为数据库查询提供高效、便捷的分页功能。Spring Boot以其简洁的配置和快速的开发体验深受开发者喜爱,而MyBatis作为轻量级持久层框架,与...

    Mybatis PageHelper分页插件是一个应用于Mybatis中的分页插件系统.rar

    分页插件PageHelper是通过mybatis的拦截器实现分页功能的,拦截sql查询请求,添加分页语句,最终实现分页查询功能。 一、分页插件PageHelper支持的数据库类型? Oracle,MySql,MariaDB,SQLite等 二、分页插件...

    mybatis分页插件源码

    下面我们将深入探讨MyBatis分页插件的相关知识点。 1. **MyBatis框架基础** MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果...

    SpringMVC+Mybatis+分页插件的实现

    自己最近搭建的一个SpringMVC+Mybatis的框架 属于无实体类的框架 并实现了Myabtis的自动分页和总数查询 只要传入分页参数便能自动查询总数和分页 总数封装在参数里面执行查询后可以直接从参数中获取

Global site tag (gtag.js) - Google Analytics