Mybatis分页-利用Mybatis Generator插件生成基于数据库方言的分页语句,统计记录总数 (转)

众所周知,Mybatis本身没有提供基于数据库方言的分页功能,而是基于JDBC的游标分页,很容易出现性能问题。网上有很多分页的解决方案,不外乎是基于Mybatis本机的插件机制,通过拦截Sql做分页。但是在像Oracle这样的数据库上,拦截器生成的Sql语句没有变量绑定,而且每次语句的都要去拦截,感觉有点浪费性能。

Mybatis Generator是Mybatis的代码生成工具,可以生成大部分的查询语句。

本文提供的分页解决方案是新增Mybatis Generator插件,在用Mybatis Generator生成Mybatis代码时,直接生成基于数据库方言的Sql语句,解决Oralce等数据库的变量绑定,且无需使用Mybatis拦截器去拦截语句判断分页。

一、编写Mybatis Generator Dialect插件

 

Java代码  收藏代码
  1. 2011 Tgwoo Inc.  
  2. //www.tgwoo.com/  
  3. package com.tgwoo.core.dao.plugin;  
  4. import java.util.List;  
  5. import org.mybatis.generator.api.CommentGenerator;  
  6. import org.mybatis.generator.api.IntrospectedTable;  
  7. import org.mybatis.generator.api.PluginAdapter;  
  8. import org.mybatis.generator.api.dom.java.Field;  
  9. import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;  
  10. import org.mybatis.generator.api.dom.java.JavaVisibility;  
  11. import org.mybatis.generator.api.dom.java.Method;  
  12. import org.mybatis.generator.api.dom.java.Parameter;  
  13. import org.mybatis.generator.api.dom.java.TopLevelClass;  
  14. import org.mybatis.generator.api.dom.xml.Attribute;  
  15. import org.mybatis.generator.api.dom.xml.Document;  
  16. import org.mybatis.generator.api.dom.xml.TextElement;  
  17. import org.mybatis.generator.api.dom.xml.XmlElement;  
  18. /** 
  19.  * @author pan.wei 
  20.  * @date 2011-11-30 下午08:36:11 
  21.  */  
  22. public class OraclePaginationPlugin extends PluginAdapter {  
  23.     @Override  
  24. public boolean modelExampleClassGenerated(TopLevelClass topLevelClass,  
  25.         // add field, getter, setter for limit clause  
  26. "page");  
  27. return super.modelExampleClassGenerated(topLevelClass,  
  28.     }  
  29.     @Override  
  30. public boolean sqlMapDocumentGenerated(Document document,  
  31.         XmlElement parentElement = document.getRootElement();  
  32.         // 产生分页语句前半部分  
  33. new XmlElement("sql");  
  34. new Attribute("id",  
  35. "OracleDialectPrefix"));  
  36. new XmlElement("if");  
  37. new Attribute("test", "page != null"));  
  38. new TextElement(  
  39. "select * from ( select row_.*, rownum rownum_ from ( "));  
  40.         parentElement.addElement(paginationPrefixElement);  
  41.         // 产生分页语句后半部分  
  42. new XmlElement("sql");  
  43. new Attribute("id",  
  44. "OracleDialectSuffix"));  
  45. new XmlElement("if");  
  46. new Attribute("test", "page != null"));  
  47. new TextElement(  
  48. "<![CDATA[ ) row_ ) where rownum_ > #{page.begin} and rownum_ <= #{page.end} ]]>"));  
  49.         parentElement.addElement(paginationSuffixElement);  
  50.         return super.sqlMapDocumentGenerated(document, introspectedTable);  
  51.   
  52. @Override  
  53. public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(  
  54.   
  55. new XmlElement("include"); //$NON-NLS-1$     
  56. new Attribute("refid", "OracleDialectPrefix"));  
  57. 0, pageStart);  
  58.         XmlElement isNotNullElement = new XmlElement("include"); //$NON-NLS-1$     
  59. new Attribute("refid",  
  60. "OracleDialectSuffix"));  
  61.   
  62. return super.sqlMapUpdateByExampleWithoutBLOBsElementGenerated(element,  
  63.     }  
  64.     /** 
  65.      * @param topLevelClass 
  66.      * @param introspectedTable 
  67.      * @param name 
  68.      */  
  69. private void addPage(TopLevelClass topLevelClass,  
  70.         topLevelClass.addImportedType(new FullyQualifiedJavaType(  
  71. "com.tgwoo.core.dao.pojo.Page"));  
  72.         Field field = new Field();  
  73.         field.setType(new FullyQualifiedJavaType("com.tgwoo.core.dao.pojo.Page"));  
  74.         commentGenerator.addFieldComment(field, introspectedTable);  
  75.         char c = name.charAt(0);  
  76. 1);  
  77. new Method();  
  78.         method.setName("set" + camel);  
  79. new Parameter(new FullyQualifiedJavaType(  
  80. "com.tgwoo.core.dao.pojo.Page"), name));  
  81. "this." + name + "=" + name + ";");  
  82.         topLevelClass.addMethod(method);  
  83. new Method();  
  84.         method.setReturnType(new FullyQualifiedJavaType(  
  85. "com.tgwoo.core.dao.pojo.Page"));  
  86. "get" + camel);  
  87. "return " + name + ";");  
  88.         topLevelClass.addMethod(method);  
  89.   
  90. /** 
  91.      * This plugin is always valid - no properties are required 
  92.      */  
  93. public boolean validate(List<String> warnings) {  
  94. return true;  
  95. }  

 

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

 

Xml代码  收藏代码
  1. >  
  2. <generatorConfiguration >  
  3. <classPathEntry location="E:\work\eclipseWorkspace\myEclipse\CTSPMTS\WebRoot\WEB-INF\lib\ojdbc14.jar" />  
  4.     <context id="oracle" >  
  5. <plugin type="org.mybatis.generator.plugins.CaseInsensitiveLikePlugin"></plugin>  
  6. <plugin type="org.mybatis.generator.plugins.SerializablePlugin"></plugin>  
  7. <!-- Pagination -->  
  8. <plugin type="com.tgwoo.core.dao.plugin.OraclePaginationPlugin"></plugin>  
  9.         <commentGenerator>    
  10. <property name="suppressDate" value="true" />    
  11. <property name="suppressAllComments" value="true" />  
  12. </commentGenerator>    
  13.         <jdbcConnection driverClass="oracle.jdbc.driver.OracleDriver" connectionURL="jdbc:oracle:thin:@192.168.0.2:1521:ctspmt" userId="ctspmt" password="ctspmt123" />  
  14. <javaModelGenerator targetPackage="com.tgwoo.ctspmt.model" targetProject="CTSPMTS/src" />  
  15. <sqlMapGenerator targetPackage="com.tgwoo.ctspmt.data" targetProject="CTSPMTS/src" />  
  16. <javaClientGenerator targetPackage="com.tgwoo.ctspmt.data" targetProject="CTSPMTS/src" type="XMLMAPPER" /><!-- 
  17.        
  18.         <table schema="ctspmt" tableName="mt_e_interface_log"/> 
  19.         --><!--  
  20. <table schema="ctspmt" tableName="mt_e_msg" />  
  21. <table schema="ctspmt" tableName="mt_e_msg_log" />  
  22. <table schema="ctspmt" tableName="mt_e_msg_receiver" />  
  23. <table schema="ctspmt" tableName="st_e_org" />  
  24. <table schema="ctspmt" tableName="st_e_role" />  
  25. <table schema="ctspmt" tableName="st_e_user" />  
  26. <table schema="ctspmt" tableName="mt_e_user_msg_conf" />  
  27. <table schema="ctspmt" tableName="mt_j_user_device" />  
  28. <table schema="ctspmt" tableName="st_j_user_role" />  
  29. <table schema="ctspmt" tableName="ST_E_UNIQUE_KEY" />       
  30. ><table schema="ctspmt" tableName="mt_v_msg_item" />  
  31. </context>  
  32. </generatorConfiguration>  

 

 

三、示例

 

Java代码  收藏代码
  1. 2011 Tgwoo Inc.  
  2. //www.tgwoo.com/  
  3. package com.tgwoo.ctspmt.test;  
  4. import com.tgwoo.core.config.SpringBeanProxy;  
  5. import com.tgwoo.core.dao.pojo.Page;  
  6. import com.tgwoo.ctspmt.data.MtVMsgItemMapper;  
  7. import com.tgwoo.ctspmt.model.MtVMsgItemExample;  
  8. /** 
  9.  * @author pan.wei 
  10.  * @date 2011-11-25 下午01:26:17 
  11.  */  
  12. public class Test {  
  13. /** 
  14.      * @param args 
  15.      */  
  16. public static void main(String[] args) {  
  17. //get spring mapper instance   
  18.                 MtVMsgItemMapper.class);  
  19. new MtVMsgItemExample();  
  20. new Page(0, 10);  
  21.         ex.createCriteria().andMsgCodeEqualTo("222");  
  22. // set count,up to you  
  23.         int row = mapper.selectByExample(ex).size();  
  24. "============row:" + row + "================");  
  25.   
  26. }  

 

四、分页类

 

Java代码  收藏代码
  1. package com.tgwoo.core.dao.pojo;  
  2. /** 
  3.  * @author pan.wei 
  4.  * @date 2011-12-1 上午11:36:12 
  5.  */  
  6. public class Page {  
  7. // 分页查询开始记录位置  
  8. private int begin;  
  9. // 分页查看下结束位置  
  10. private int end;  
  11. // 每页显示记录数  
  12. private int length;  
  13. // 查询结果总记录数  
  14. private int count;  
  15. // 当前页码  
  16. private int current;  
  17. // 总共页数  
  18. private int total;  
  19.     public Page() {  
  20.   
  21. /** 
  22.      * 构造函数 
  23.      *  
  24.      * @param begin 
  25.      * @param length 
  26.      */  
  27. public Page(int begin, int length) {  
  28. this.begin = begin;  
  29. this.length = length;  
  30. this.end = this.begin + this.length;  
  31. this.current = (int) Math.floor((this.begin * 1.0d) / this.length) + 1;  
  32.   
  33. /** 
  34.      * @param begin 
  35.      * @param length 
  36.      * @param count 
  37.      */  
  38. public Page(int begin, int length, int count) {  
  39. this(begin, length);  
  40. this.count = count;  
  41.   
  42. /** 
  43.      * @return the begin 
  44.      */  
  45. public int getBegin() {  
  46. return begin;  
  47.   
  48. /** 
  49.      * @return the end 
  50.      */  
  51. public int getEnd() {  
  52. return end;  
  53.   
  54. /** 
  55.      * @param end 
  56.      *            the end to set 
  57.      */  
  58. public void setEnd(int end) {  
  59. this.end = end;  
  60.   
  61. /** 
  62.      * @param begin 
  63.      *            the begin to set 
  64.      */  
  65. public void setBegin(int begin) {  
  66. this.begin = begin;  
  67. if (this.length != 0) {  
  68. this.current = (int) Math.floor((this.begin * 1.0d) / this.length) + 1;  
  69.     }  
  70.     /** 
  71.      * @return the length 
  72.      */  
  73. public int getLength() {  
  74. return length;  
  75.   
  76. /** 
  77.      * @param length 
  78.      *            the length to set 
  79.      */  
  80. public void setLength(int length) {  
  81. this.length = length;  
  82. if (this.begin != 0) {  
  83. this.current = (int) Math.floor((this.begin * 1.0d) / this.length) + 1;  
  84.     }  
  85.     /** 
  86.      * @return the count 
  87.      */  
  88. public int getCount() {  
  89. return count;  
  90.   
  91. /** 
  92.      * @param count 
  93.      *            the count to set 
  94.      */  
  95. public void setCount(int count) {  
  96. this.count = count;  
  97. this.total = (int) Math.floor((this.count * 1.0d) / this.length);  
  98. if (this.count % this.length != 0) {  
  99. this.total++;  
  100.     }  
  101.     /** 
  102.      * @return the current 
  103.      */  
  104. public int getCurrent() {  
  105. return current;  
  106.   
  107. /** 
  108.      * @param current 
  109.      *            the current to set 
  110.      */  
  111. public void setCurrent(int current) {  
  112. this.current = current;  
  113.   
  114. /** 
  115.      * @return the total 
  116.      */  
  117. public int getTotal() {  
  118. if (total == 0) {  
  119. return 1;  
  120.         return total;  
  121.   
  122. /** 
  123.      * @param total 
  124.      *            the total to set 
  125.      */  
  126. public void setTotal(int total) {  
  127. this.total = total;  
  128.   
  129. }  

 五、生成后的代码

1、Example代码

 

 

Java代码  收藏代码
  1. package com.tgwoo.ctspmt.model;  
  2. import com.tgwoo.core.dao.pojo.Page;  
  3. import java.math.BigDecimal;  
  4. import java.util.ArrayList;  
  5. import java.util.Date;  
  6. import java.util.Iterator;  
  7. import java.util.List;  
  8. public class MtVMsgItemExample {  
  9. protected String orderByClause;  
  10.     protected boolean distinct;  
  11.     protected List<Criteria> oredCriteria;  
  12.     protected Page page;  
  13.     ...  

 2、mapper.xml

 

Xml代码  收藏代码
  1.  <select id="selectByExample" resultMap="BaseResultMap" parameterType="com.tgwoo.ctspmt.model.MtVMsgItemExample" >  
  2. <include refid="OracleDialectPrefix" />  
  3.     <if test="distinct" >  
  4.     </if>  
  5. <include refid="Base_Column_List" />  
  6.     <if test="_parameter != null" >  
  7. <include refid="Example_Where_Clause" />  
  8. </if>  
  9. <if test="orderByClause != null" >  
  10.     </if>  
  11. <include refid="OracleDialectSuffix" />  
  12. </select>  
  13.   <sql id="OracleDialectPrefix" >  
  14. <if test="page != null" >  
  15.     </if>  
  16. </sql>  
  17. <sql id="OracleDialectSuffix" >  
  18. <if test="page != null" >  
  19. <![CDATA[ ) row_ ) where rownum_ > #{page.begin} and rownum_ <= #{page.end} ]]>  
  20. </if>  
  21. </sql>  
  22. ...  

 

 

附件是Mybatis Generatorjar包。

其他数据库的方言可以按照Oracle的去改写,有写好的希望能共享下。

 

 

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

maven管理:

1、pom.xml

 

Xml代码  收藏代码
  1. <build>  
  2. <plugins>  
  3. <plugin>  
  4. <groupId>org.mybatis.generator</groupId>  
  5. <artifactId>mybatis-generator-maven-plugin</artifactId>  
  6. <version>1.3.1</version>  
  7. <executions>  
  8. <execution>  
  9. <id>Generate MyBatis Artifacts</id>  
  10. <goals>  
  11. <goal>generate</goal>  
  12. </goals>  
  13. </execution>  
  14. </executions>  
  15. <dependencies>  
  16. <dependency>  
  17. <groupId>com.oracle</groupId>  
  18. <artifactId>ojdbc14</artifactId>  
  19. <version>10.2.0.4.0</version>  
  20. </dependency>  
  21. </dependencies>  
  22. </plugin>  
  23. </plugins>  
  24. </build>  

 

 

Xml代码  收藏代码
  1.   

 

 2、generatorConfig.xml

 

Xml代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.   PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"  
  3. >  
  4. <generatorConfiguration>  
  5. <context id="oracleGenerator" targetRuntime="MyBatis3">  
  6. <plugin type="org.mybatis.generator.plugins.CaseInsensitiveLikePlugin"></plugin>  
  7. <plugin type="org.mybatis.generator.plugins.SerializablePlugin"></plugin>  
  8. <!-- Pagination -->  
  9. <plugin  
  10. type="com.tgwoo.test.core.dao.mybatis.generator.plugin.pagination.OraclePaginationPlugin"></plugin>  
  11.         <!-- 取消注释 -->  
  12. <commentGenerator>  
  13. <property name="suppressDate" value="true" />  
  14. <property name="suppressAllComments" value="true" />  
  15. </commentGenerator>  
  16. <!-- 配置连接数据信息 -->  
  17. <jdbcConnection driverClass="oracle.jdbc.driver.OracleDriver"  
  18. connectionURL="jdbc:oracle:thin:@192.168.0.2:1521:test" userId="test"  
  19. password="test123" />  
  20. <javaTypeResolver>  
  21. <property name="forceBigDecimals" value="false" />  
  22. </javaTypeResolver>  
  23.         <!-- 配置自动生成的Model的保存路径与其它参数 -->  
  24. <javaModelGenerator targetPackage="com.tgwoo.test.dao.model"  
  25. targetProject=".\src\main\java">  
  26. <property name="enableSubPackages" value="false" />  
  27. <property name="trimStrings" value="true" />  
  28. </javaModelGenerator>  
  29.         <!-- 配置自动生成的Mappper.xml映射的保存路径与其它参数 -->  
  30. <sqlMapGenerator targetPackage="com.tgwoo.test.dao"  
  31. targetProject=".\src\main\resources">  
  32. <property name="enableSubPackages" value="false" />  
  33. </sqlMapGenerator>  
  34.         <!-- 配置自动生成的Mappper.java接口的保存路径与其它参数 -->  
  35. <javaClientGenerator type="XMLMAPPER"  
  36. targetPackage="com.tgwoo.test.dao" targetProject=".\src\main\java">  
  37. <property name="enableSubPackages" value="false" />  
  38. </javaClientGenerator>  
  39.         <!-- 生成表对应的操作与实体对象 -->  
  40. <table schema="test" tableName="testTable">  
  41. <columnOverride column="id" javaType="Long" />  
  42. </table>  
  43. </context>  
  44. </generatorConfiguration>  

 

 3、run

Goals:mybatis-generator:generate

 

4、注意事项

报插件无法找到或者无法实例化的一般是分页插件和maven插件不在同一classloader下引起的,需要在mybatis-generator-maven-plugin的dependencies中增加dependency。

posted on 2017-03-05 18:18  xiaopangzhi  阅读(427)  评论(0编辑  收藏  举报