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

时间:2020-11-25 16:01:43

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

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

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

一、编写Mybatis Generator Dialect插件

  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. @Override
  52. public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(
  53. new XmlElement("include"); //$NON-NLS-1$
  54. new Attribute("refid", "OracleDialectPrefix"));
  55. 0, pageStart);
  56. XmlElement isNotNullElement = new XmlElement("include"); //$NON-NLS-1$
  57. new Attribute("refid",
  58. "OracleDialectSuffix"));
  59. return super.sqlMapUpdateByExampleWithoutBLOBsElementGenerated(element,
  60. }
  61. /**
  62. * @param topLevelClass
  63. * @param introspectedTable
  64. * @param name
  65. */
  66. private void addPage(TopLevelClass topLevelClass,
  67. topLevelClass.addImportedType(new FullyQualifiedJavaType(
  68. "com.tgwoo.core.dao.pojo.Page"));
  69. Field field = new Field();
  70. field.setType(new FullyQualifiedJavaType("com.tgwoo.core.dao.pojo.Page"));
  71. commentGenerator.addFieldComment(field, introspectedTable);
  72. char c = name.charAt(0);
  73. 1);
  74. new Method();
  75. method.setName("set" + camel);
  76. new Parameter(new FullyQualifiedJavaType(
  77. "com.tgwoo.core.dao.pojo.Page"), name));
  78. "this." + name + "=" + name + ";");
  79. topLevelClass.addMethod(method);
  80. new Method();
  81. method.setReturnType(new FullyQualifiedJavaType(
  82. "com.tgwoo.core.dao.pojo.Page"));
  83. "get" + camel);
  84. "return " + name + ";");
  85. topLevelClass.addMethod(method);
  86. /**
  87. * This plugin is always valid - no properties are required
  88. */
  89. public boolean validate(List<String> warnings) {
  90. return true;
  91. }

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

  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. <table schema="ctspmt" tableName="mt_e_interface_log"/>
  18. --><!--
  19. <table schema="ctspmt" tableName="mt_e_msg" />
  20. <table schema="ctspmt" tableName="mt_e_msg_log" />
  21. <table schema="ctspmt" tableName="mt_e_msg_receiver" />
  22. <table schema="ctspmt" tableName="st_e_org" />
  23. <table schema="ctspmt" tableName="st_e_role" />
  24. <table schema="ctspmt" tableName="st_e_user" />
  25. <table schema="ctspmt" tableName="mt_e_user_msg_conf" />
  26. <table schema="ctspmt" tableName="mt_j_user_device" />
  27. <table schema="ctspmt" tableName="st_j_user_role" />
  28. <table schema="ctspmt" tableName="ST_E_UNIQUE_KEY" />
  29. ><table schema="ctspmt" tableName="mt_v_msg_item" />
  30. </context>
  31. </generatorConfiguration>

三、示例

  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. }

四、分页类

  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. * @param begin
  24. * @param length
  25. */
  26. public Page(int begin, int length) {
  27. this.begin = begin;
  28. this.length = length;
  29. this.end = this.begin + this.length;
  30. this.current = (int) Math.floor((this.begin * 1.0d) / this.length) + 1;
  31. /**
  32. * @param begin
  33. * @param length
  34. * @param count
  35. */
  36. public Page(int begin, int length, int count) {
  37. this(begin, length);
  38. this.count = count;
  39. /**
  40. * @return the begin
  41. */
  42. public int getBegin() {
  43. return begin;
  44. /**
  45. * @return the end
  46. */
  47. public int getEnd() {
  48. return end;
  49. /**
  50. * @param end
  51. *            the end to set
  52. */
  53. public void setEnd(int end) {
  54. this.end = end;
  55. /**
  56. * @param begin
  57. *            the begin to set
  58. */
  59. public void setBegin(int begin) {
  60. this.begin = begin;
  61. if (this.length != 0) {
  62. this.current = (int) Math.floor((this.begin * 1.0d) / this.length) + 1;
  63. }
  64. /**
  65. * @return the length
  66. */
  67. public int getLength() {
  68. return length;
  69. /**
  70. * @param length
  71. *            the length to set
  72. */
  73. public void setLength(int length) {
  74. this.length = length;
  75. if (this.begin != 0) {
  76. this.current = (int) Math.floor((this.begin * 1.0d) / this.length) + 1;
  77. }
  78. /**
  79. * @return the count
  80. */
  81. public int getCount() {
  82. return count;
  83. /**
  84. * @param count
  85. *            the count to set
  86. */
  87. public void setCount(int count) {
  88. this.count = count;
  89. this.total = (int) Math.floor((this.count * 1.0d) / this.length);
  90. if (this.count % this.length != 0) {
  91. this.total++;
  92. }
  93. /**
  94. * @return the current
  95. */
  96. public int getCurrent() {
  97. return current;
  98. /**
  99. * @param current
  100. *            the current to set
  101. */
  102. public void setCurrent(int current) {
  103. this.current = current;
  104. /**
  105. * @return the total
  106. */
  107. public int getTotal() {
  108. if (total == 0) {
  109. return 1;
  110. return total;
  111. /**
  112. * @param total
  113. *            the total to set
  114. */
  115. public void setTotal(int total) {
  116. this.total = total;
  117. }

五、生成后的代码

1、Example代码

  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

  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

  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>

2、generatorConfig.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。