MyIbatis學習 (二)--利用Generator插件生成基於數據庫方言的分頁語句

衆所周知,Mybatis本身沒有提供基於數據庫方言的分頁功能,而是基於JDBC的遊標分頁,很容易出現性能問題。網上有很多分頁的解決方案,不外乎是基於Mybatis本機的插件機制,通過攔截Sql做分頁。但是在像Oracle這樣的數據庫上,攔截器生成的Sql語句沒有變量綁定,而且每次語句的都要去攔截,感覺有點浪費性能。

Mybatis Generator是Mybatis的代碼生成工具,可以生成大部分的查詢語句。

本文提供的分頁解決方案是新增Mybatis Generator插件,在用Mybatis Generator生成Mybatis代碼時,直接生成基於數據庫方言的Sql語句,解決Oralce等數據庫的變量綁定,且無需使用Mybatis攔截器去攔截語句判斷分頁。

一、編寫分頁對象

package com.page;

import java.util.List;


/** 
* @Description: Page類
* @author BRUCE
* @date 2014年11月5日 下午8:05:07 
* 
* @param <T> 
*/
public class Page<T> {
	public static final int DEFAULT_PAGE_SIZE = 15;
	// 分頁查詢開始記錄位置
	private int begin;
	// 分頁查看下結束位置
	private int end;
	// 每頁顯示記錄數
	private int length;
	// 查詢結果總記錄數
	private int totalRecords;
	// 當前頁碼
	private int currentPage;
	// 總共頁數
	private int totalPage;
	//對應的當前頁記錄
	private List<T> resultList;
	
	
	public Page() {
		this.currentPage = 1;
        this.length = DEFAULT_PAGE_SIZE;
        this.begin = (getCurrentPage() - 1) * getLength();
        this.end = getCurrentPage() * getLength();
	}

	/**
	 * 構造函數
	 * 
	 * @param begin
	 * @param length
	 */
	public Page(int begin, int length) {
		this.begin = begin;
		this.length = length;
		this.end = this.begin + this.length;
		this.currentPage = (int) Math.floor((this.begin * 1.0d) / this.length) + 1;
	}

	/**
	 * @param begin
	 * @param length
	 * @param totalRecords
	 */
	public Page(int begin, int length, int totalRecords) {
		this(begin, length);
		this.totalRecords = totalRecords;
	}

	  /**
     * 設置頁數,自動計算數據範圍.
     * 
     * @param currentPage
     */
    public Page(int currentPage) {        
    	this.currentPage = currentPage;
    	currentPage = currentPage > 0 ? currentPage : 1;  
        this.begin = this.length * (currentPage - 1);        
        this.end = this.length * currentPage;
    } 
	/**
	 * @return the begin
	 */
	public int getBegin() {
		return begin;
	}

	/**
	 * @return the end
	 */
	public int getEnd() {
		return end;
	}

	/**
	 * @param end
	 *            the end to set
	 */
	public void setEnd(int end) {
		this.end = end;
	}

	/**
	 * @param begin
	 *            the begin to set
	 */
	public void setBegin(int begin) {
		this.begin = begin;
		if (this.length != 0) {
			this.currentPage = (int) Math.floor((this.begin * 1.0d) / this.length) + 1;
		}
	}

	/**
	 * @return the length
	 */
	public int getLength() {
		return length;
	}

	/**
	 * @param length
	 *            the length to set
	 */
	public void setLength(int length) {
		this.length = length;
		if (this.begin != 0) {
			this.currentPage = (int) Math.floor((this.begin * 1.0d) / this.length) + 1;
		}
	}

	/**
	 * @return the totalRecords
	 */
	public int getTotalRecords() {
		return totalRecords;
	}

	/**
	 * @param totalRecords
	 *            the totalRecords to set
	 */
	public void setTotalRecords(int totalRecords) {
		this.totalRecords = totalRecords;
		this.totalPage = (int) Math.floor((this.totalRecords * 1.0d) / this.length);
		if (this.totalRecords % this.length != 0) {
			this.totalPage++;
		}
	}

	/**
	 * @return the currentPage
	 */
	public int getCurrentPage() {
		return currentPage;
	}

	/**
	 * @param currentPage
	 *            the currentPage to set
	 */
	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	    this.currentPage = currentPage;
	    currentPage = currentPage > 0 ? currentPage : 1;
        this.begin = this.length * (currentPage - 1);
        this.end = this.length * currentPage;
	}

	/**
	 * @return the totalPage
	 */
	public int getTotalPage() {
		if (totalPage == 0) {
			return 1;
		}
		return totalPage;
	}

	/**
	 * @param totalPage
	 *            the totalPage to set
	 */
	public void setTotalPage(int totalPage) {
		this.totalPage = totalPage;
	}
	
	 public List<T> getResultList() {
		return resultList;
	}

	public void setResultList(List<T> resultList) {
		this.resultList = resultList;
	}

	@Override
	 public String toString() {        
		 final StringBuilder builder = new StringBuilder("begin=").append(begin).append(", end=")
             .append(end).append(", length=").append(length).append(", totalRecords=").append(
            		 totalRecords).append(", currentPage=").append(currentPage).append(", totalPage=")
             .append(totalPage);
		 return builder.toString();
 }
}


二、編寫Mybatis Generator Oracle Dialect插件

package com.page.plugin;

import java.util.List;

import org.mybatis.generator.api.CommentGenerator;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;

/**
 * @Description: Myibatis對應的Oracle分頁插件
 * @author BRUCE
 * @date 2014年11月5日 下午5:48:40
 * 
 */
public class OraclePaginationPlugin extends PluginAdapter {

	/**
	 * Page類所在的類路徑:其中Page類中一定要有begin和end屬性(即:開始記錄位置和結束記錄位置)
	 */
	public static final String pageClassPath = "com.page.Page";

	@Override
	public boolean modelExampleClassGenerated(TopLevelClass topLevelClass,
			IntrospectedTable introspectedTable) {
		// add field, getter, setter for limit clause
		addPage(topLevelClass, introspectedTable, "page");
		return super.modelExampleClassGenerated(topLevelClass,
				introspectedTable);
	}

	@Override
	public boolean sqlMapDocumentGenerated(Document document,
			IntrospectedTable introspectedTable) {
		XmlElement parentElement = document.getRootElement();

		// 產生分頁語句前半部分
		XmlElement paginationPrefixElement = new XmlElement("sql");
		paginationPrefixElement.addAttribute(new Attribute("id",
				"OracleDialectPrefix"));
		XmlElement pageStart = new XmlElement("if");
		pageStart.addAttribute(new Attribute("test", "page != null"));
		pageStart.addElement(new TextElement(
				"select * from ( select row_.*, rownum rownum_ from ( "));
		paginationPrefixElement.addElement(pageStart);
		parentElement.addElement(paginationPrefixElement);

		// 產生分頁語句後半部分
		XmlElement paginationSuffixElement = new XmlElement("sql");
		paginationSuffixElement.addAttribute(new Attribute("id",
				"OracleDialectSuffix"));
		XmlElement pageEnd = new XmlElement("if");
		pageEnd.addAttribute(new Attribute("test", "page != null"));
		pageEnd.addElement(new TextElement(
				"<![CDATA[ ) row_ ) where rownum_ > #{page.begin} and rownum_ <= #{page.end} ]]>"));
		paginationSuffixElement.addElement(pageEnd);
		parentElement.addElement(paginationSuffixElement);

		return super.sqlMapDocumentGenerated(document, introspectedTable);
	}

	@Override
	public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(
			XmlElement element, IntrospectedTable introspectedTable) {

		XmlElement pageStart = new XmlElement("include"); //$NON-NLS-1$   
		pageStart.addAttribute(new Attribute("refid", "OracleDialectPrefix"));
		element.getElements().add(0, pageStart);

		XmlElement isNotNullElement = new XmlElement("include"); //$NON-NLS-1$   
		isNotNullElement.addAttribute(new Attribute("refid",
				"OracleDialectSuffix"));
		element.getElements().add(isNotNullElement);

		return super.sqlMapUpdateByExampleWithoutBLOBsElementGenerated(element,
				introspectedTable);
	}

	/**
	 * @param topLevelClass
	 * @param introspectedTable
	 * @param name
	 */
	private void addPage(TopLevelClass topLevelClass,
			IntrospectedTable introspectedTable, String name) {
		topLevelClass
				.addImportedType(new FullyQualifiedJavaType(pageClassPath));
		CommentGenerator commentGenerator = context.getCommentGenerator();
		Field field = new Field();
		field.setVisibility(JavaVisibility.PROTECTED);
		field.setType(new FullyQualifiedJavaType(pageClassPath));
		field.setName(name);
		commentGenerator.addFieldComment(field, introspectedTable);
		topLevelClass.addField(field);
		char c = name.charAt(0);
		String camel = Character.toUpperCase(c) + name.substring(1);
		Method method = new Method();
		method.setVisibility(JavaVisibility.PUBLIC);
		method.setName("set" + camel);
		method.addParameter(new Parameter(new FullyQualifiedJavaType(
				pageClassPath), name));
		method.addBodyLine("this." + name + "=" + name + ";");
		commentGenerator.addGeneralMethodComment(method, introspectedTable);
		topLevelClass.addMethod(method);
		method = new Method();
		method.setVisibility(JavaVisibility.PUBLIC);
		method.setReturnType(new FullyQualifiedJavaType(pageClassPath));
		method.setName("get" + camel);
		method.addBodyLine("return " + name + ";");
		commentGenerator.addGeneralMethodComment(method, introspectedTable);
		topLevelClass.addMethod(method);
	}

	/**
	 * This plugin is always valid - no properties are required
	 */
	public boolean validate(List<String> warnings) {
		return true;
	}
}

三、編寫Mybatis Generator MySQL Dialect插件

package com.page.plugin;

import java.util.List;

import org.mybatis.generator.api.CommentGenerator;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;

/** 
* @Description: Myibatis對應的MySQL分頁插件
* @author BRUCE
* @date 2014年11月5日 下午8:04:23 
*  
*/
public final class MySQLPaginationPlugin extends PluginAdapter {

	/**
	 * Page類所在的類路徑:其中Page類中一定要有begin和length屬性(即:開始記錄位置和每頁的記錄數)
	 */
	public static final String pageClassPath = "com.page.Page";
    @Override
    public boolean modelExampleClassGenerated(TopLevelClass topLevelClass,
            IntrospectedTable introspectedTable) {        // add field, getter, setter for limit clause
        addPage(topLevelClass, introspectedTable, "page");        return super.modelExampleClassGenerated(topLevelClass, introspectedTable);
    }    @Override
    public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element,
            IntrospectedTable introspectedTable) {
        XmlElement page = new XmlElement("if");
        page.addAttribute(new Attribute("test", "page != null"));
        page.addElement(new TextElement("limit #{page.begin} , #{page.length}"));
        element.addElement(page);        return super.sqlMapUpdateByExampleWithoutBLOBsElementGenerated(element, introspectedTable);
    }    /**
     * @param topLevelClass
     * @param introspectedTable
     * @param name
     */
    private void addPage(TopLevelClass topLevelClass, IntrospectedTable introspectedTable,
            String name) {
        topLevelClass.addImportedType(new FullyQualifiedJavaType(pageClassPath));
        CommentGenerator commentGenerator = context.getCommentGenerator();
        Field field = new Field();
        field.setVisibility(JavaVisibility.PROTECTED);
        field.setType(new FullyQualifiedJavaType(pageClassPath));
        field.setName(name);
        commentGenerator.addFieldComment(field, introspectedTable);
        topLevelClass.addField(field);        char c = name.charAt(0);
        String camel = Character.toUpperCase(c) + name.substring(1);
        Method method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName("set" + camel);
        method.addParameter(new Parameter(new FullyQualifiedJavaType(pageClassPath), name));
        method.addBodyLine("this." + name + "=" + name + ";");
        commentGenerator.addGeneralMethodComment(method, introspectedTable);
        topLevelClass.addMethod(method);
        method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setReturnType(new FullyQualifiedJavaType(pageClassPath));
        method.setName("get" + camel);
        method.addBodyLine("return " + name + ";");
        commentGenerator.addGeneralMethodComment(method, introspectedTable);
        topLevelClass.addMethod(method);
    }    /**
     * This plugin is always valid - no properties are required
     */
    public boolean validate(List<String> warnings) {       
    	return true;
    }
}

四、增加插件到Mybatis Generator配置文件中

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration >
  <classPathEntry location="D:/ojdbc5-11.2.0.2.0.jar" />
  
  <context id="context1" >
  <plugin type="org.mybatis.generator.plugins.CaseInsensitiveLikePlugin"></plugin>  
  <plugin type="org.mybatis.generator.plugins.SerializablePlugin"></plugin>
  <!-- Pagination:Oracle -->  
   <plugin  type="com.page.plugin.OraclePaginationPlugin"></plugin>
   <!-- Pagination:MySql -->  
  <!--  <plugin  type="com.page.plugin.MySQLPaginationPlugin"></plugin> -->
  
   <!-- 取消註釋 --> 
   <commentGenerator>    
      <property name="suppressDate" value="true" />    
      <property name="suppressAllComments" value="true" />  
   </commentGenerator> 
  	<!-- 配置連接數據信息 -->  
    <jdbcConnection driverClass="oracle.jdbc.driver.OracleDriver" connectionURL="jdbc:oracle:thin:@192.168.1.233:1521:orcl" userId="cmss" password="cmss" />
    
	 <!-- 配置自動生成的Model的保存路徑與其它參數 --> 
	 <javaModelGenerator targetPackage="com.entity.main" targetProject="MyIbatisGeneratorForPage\src\main\java" />
	 <!-- 配置自動生成的Mappper.xml映射的保存路徑與其它參數 -->  	
	<sqlMapGenerator targetPackage="config.myibatis.xml" targetProject="MyIbatisGeneratorForPage\src\main\resources" />
	<!-- 配置自動生成的Mappper.java接口的保存路徑與其它參數 -->  	
	<javaClientGenerator targetPackage="com.dao" targetProject="MyIbatisGeneratorForPage\src\main\java" type="XMLMAPPER" />
	
  <!--    <table schema="" tableName="T_SYS_USER"></table>
    <table schema="" tableName="T_SYS_ROLE"></table>
    <table schema="" tableName="T_SYS_ORG"></table>
    <table schema="" tableName="T_SYS_ROLE_RES"></table>
    <table schema="" tableName="T_SYS_RESOURCE"></table>
    <table schema="" tableName="T_SYS_USER_ROLE"></table>
    <table schema="" tableName="T_SYS_CONFIG"></table>
    <table schema="" tableName="T_SYS_LOG"></table>
    <table schema="" tableName="T_SYS_CODE"></table>
    <table schema="" tableName="T_CORE_PARAM"></table>
     -->
     <!-- 生成表對應的操作與實體對象 -->  
     <table schema="" tableName="T_CORE_ORG_HIS">
     	<columnOverride column="id" javaType="Long" />  
     </table>
  </context>
</generatorConfiguration>



五、測試

import com.jiuyu.cms.entity.main.TCoreOrgExample;
import com.jiuyu.cms.entity.main.TCoreOrgexampleample;
import com.jiuyu.cms.entity.main.TCoreOrgexampleample.Criteria;
import com.jiuyv.util.Page;
import com.jiuyv.Dao.TCoreOrgMapper;


/** 
* @Description: 測試類
* @author BRUCE
* @date 2014年11月5日 下午8:30:50 
*  
*/
public class Test {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		//get spring mapper instance 
		TCoreOrgMapper mapper = SpringBeanProxy.getCtx().getBean(
				TCoreOrgMapper.class);
		Page page = new Page(0, 10);
		TCoreOrgExample example = new TCoreOrgExample();
		
		Criteria criteria = example.createCriteria();
		criteria.andMsgCodeEqualTo("222");
		criteria.andOrgIdLike("%8888888888888%");
		
		example.setPage(page);
		example.setOrderByClause("LAST_UPD_TM DESC");//根據LAST_UPD_TM排序
		// set count,up to you
		page.setTotalRecords(mapper.countByexample(example));
		page.setResultList(mapper.selectByexample(example));
		int row = mapper.selectByexample(example).size();
		System.out.println("============row:" + row + "================");
	}

}





------------------------------------------------------------------------------------------------------------------------------------------------------------------



maven管理pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.jiuyu</groupId>
    <artifactId>CmsConsole</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>CmsConsole Maven Webapp</name>
    <url>http://maven.apache.org</url>

    <repositories>
        <repository>
            <id>repo1</id>
            <name>maven.org</name>
            <url>http://repo1.maven.org/maven2/</url>
        </repository>
        <repository>
            <id>jboss</id>
            <name>jboss</name>
            <url>http://repository.jboss.org/maven2/</url>
        </repository>
        <repository>
            <id>geotools</id>
            <name>geotools</name>
            <url>http://maven.geotools.fr/repository/</url>
        </repository>
        <repository>
            <id>jahia</id>
            <name>jahia</name>
            <url>http://maven.jahia.org/maven2/</url>
        </repository>
        <repository>
            <id>vars</id>
            <name>vars</name>
            <url>http://vars.sourceforge.net/maven2/</url>
        </repository>
        <repository>
            <id>jasper</id>
            <name>jasper</name>
            <url>http://jasperreports.sourceforge.net/maven2/</url>
        </repository>
        <repository>
            <id>mirrors.ibiblio.org</id>
            <name>mirrors.ibiblio.org</name>
            <url>http://mirrors.ibiblio.org/pub/mirrors/maven2/</url>
        </repository>
        <repository>
            <id>apache.nexus</id>
            <name>ASF Nexus Staging</name>
            <url>https://repository.apache.org/content/groups/staging/</url>
        </repository>
        <repository>
            <id>compass-project.org</id>
            <name>Compass</name>
            <url>http://repo.compass-project.org</url>
        </repository>
        <repository>
            <id>atlassian</id>
            <name>atlassian</name>
            <url>http://repository.atlassian.com/maven2</url>
        </repository>
    </repositories>



    <dependencies>
       <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.1.1</version>
        </dependency>
		<dependency>
			<groupId>org.mybatis.generator</groupId>
			<artifactId>mybatis-generator-core</artifactId>
			<version>1.3.2</version>
		</dependency>
    </dependencies>
</project>



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章