经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » MyBatis » 查看文章
MyBatis Generator实现MySQL分页插件 - Zou-Wang
来源:cnblogs  作者:Zou-Wang  时间:2019/6/6 8:38:57  对本文有异议

MyBatis Generator是一个非常方便的代码生成工具,它能够根据表结构生成CRUD代码,可以满足大部分需求。但是唯一让人不爽的是,生成的代码中的数据库查询没有分页功能。本文介绍如何让MyBatis Generator生成的代码具有分页功能。

MyBatis Generator结合Maven的配置和使用


在实现分页之前,首先简单介绍MyBatis Generator如何使用。

MyBatis Generator配置文件

MyBatis Generator通常会有一个xml配置文件,用来指定连接的数据库、哪些表、如何生成代码。详情可以参考官方文档:http://www.mybatis.org/generator/configreference/xmlconfig.html 。下面给出一份简单的配置,
文件命名为generatorConfig.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE generatorConfiguration
  3.   PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  4.   "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
  5. <generatorConfiguration>
  6.     <context id="mysqlgenerator" targetRuntime="MyBatis3">
  7.         <jdbcConnection driverClass="com.mysql.jdbc.Driver"
  8.             connectionURL="jdbc:mysql://localhost:3306/yourdb?useUnicode=true&amp;characterEncoding=UTF-8"
  9.             userId="user" password="password" />
  10.         <javaModelGenerator targetPackage="com.xxg.bean" targetProject="src/main/java" />
  11.         <sqlMapGenerator targetPackage="com.xxg.mapper" targetProject="src/main/resources" />
  12.         <javaClientGenerator type="XMLMAPPER" targetPackage="com.xxg.mapper" targetProject="src/main/java" />
  13.         <table tableName="table_a" />
  14.         <table tableName="table_b" />
  15.         <table tableName="table_c" />
  16.         <table tableName="table_d" />
  17.     </context>
  18. </generatorConfiguration>

Maven配置

官网文档中提供了四种MyBatis Generator生成代码的运行方式:命令行、使用Ant、使用Maven、Java编码。本文采用Maven插件mybatis-generator-maven-plugin来运行MyBatis Generator,详细配置同样可以参考官方文档:http://www.mybatis.org/generator/running/runningWithMaven.html 。

下面给出一份简单的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.2</version>
  7. <dependencies>
  8. <dependency>
  9. <groupId>mysql</groupId>
  10. <artifactId>mysql-connector-java</artifactId>
  11. <version>5.1.34</version>
  12. </dependency>
  13. </dependencies>
  14. <configuration>
  15. <overwrite>true</overwrite>
  16. </configuration>
  17. </plugin>
  18. </plugins>
  19. </build>

以上配置完成后,可以通过运行mvn mybatis-generator:generate命令来生成代码。当然,如果只有上面的这些配置,生成的代码是不支持分页的。

RowBoundsPlugin


MyBatis Generator可以通过插件机制来扩展其功能,其中RowBoundsPlugin是MyBatis Generator中自带的一个分页插件。可以在MyBatis Generator配置文件generatorConfig.xml中添加这个插件:

  1. <context id="mysqlgenerator" targetRuntime="MyBatis3">
  2. <plugin type="org.mybatis.generator.plugins.RowBoundsPlugin"></plugin>
  3. ...
  4. </context>

再次运行mvn mybatis-generator:generate生成代码,此时会发现生成的Mapper中会加入一个新的方法:selectByExampleWithRowbounds(XxxExample example, RowBounds rowBounds),可以在代码中调用这个方法来实现分页:

  1. int offset = 100;
  2. int limit = 25;
  3. RowBounds rowBounds = new RowBounds(offset, limit);
  4. List<Xxx> list = xxxMapper.selectByExampleWithRowbounds(example, rowBounds);

RowBounds的构造方法new RowBounds(offset, limit)中的offset、limit参数就相当于MySQL的select语句limit后的offset和rows。如果此时仔细观察一下日志打出来的SQL语句或者看下生成的XxxMapper.xml文件中的selectByExampleWithRowbounds元素,可以发现select语句并没有使用limit。实际上RowBounds原理是通过ResultSet的游标来实现分页,也就是并不是用select语句的limit分页而是用Java代码分页,查询语句的结果集会包含符合查询条件的所有数据,使用不慎会导致性能问题,所以并不推荐使用RowBoundsPlugin来实现分页。

limit分页插件实现


在实现MySQL分页时更推荐使用select语句的limit来实现分页,然而MyBatis Generator目前并没有提供这样的插件。好在MyBatis Generator支持插件扩展,我们可以自己实现一个基于limit来分页的插件。如何实现一个插件可以参考官方文档:http://www.mybatis.org/generator/reference/pluggingIn.html 。

实现思路
在生成的XxxExample中加入两个属性limit和offset,同时加上set和get方法。也就是需要生成以下代码:

  1. private Integer limit;
  2. private Integer offset;
  3. public void setLimit(Integer limit) {
  4. this.limit = limit;
  5. }
  6. public Integer getLimit() {
  7. return limit;
  8. }
  9. public void setOffset(Integer offset) {
  10. this.offset = offset;
  11. }
  12. public Integer getOffset() {
  13. return offset;
  14. }

XxxMapper.xml中在通过selectByExample查询时,添加limit:

  1. <select id="selectByExample" parameterType="com.xxg.bean.XxxExample" resultMap="BaseResultMap">
  2. ...
  3. <if test="limit != null">
  4. <if test="offset != null">
  5. limit ${offset}, ${limit}
  6. </if>
  7. <if test="offset == null">
  8. limit ${limit}
  9. </if>
  10. </if>
  11. </select>

插件实现代码

  1. package com.xxg.mybatis.plugins;
  2. import java.util.List;
  3. import org.mybatis.generator.api.IntrospectedTable;
  4. import org.mybatis.generator.api.PluginAdapter;
  5. import org.mybatis.generator.api.dom.java.Field;
  6. import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
  7. import org.mybatis.generator.api.dom.java.JavaVisibility;
  8. import org.mybatis.generator.api.dom.java.Method;
  9. import org.mybatis.generator.api.dom.java.Parameter;
  10. import org.mybatis.generator.api.dom.java.PrimitiveTypeWrapper;
  11. import org.mybatis.generator.api.dom.java.TopLevelClass;
  12. import org.mybatis.generator.api.dom.xml.Attribute;
  13. import org.mybatis.generator.api.dom.xml.TextElement;
  14. import org.mybatis.generator.api.dom.xml.XmlElement;
  15. public class MySQLLimitPlugin extends PluginAdapter {
  16. @Override
  17. public boolean validate(List<String> list) {
  18. return true;
  19. }
  20. /**
  21. * 为每个Example类添加limit和offset属性已经set、get方法
  22. */
  23. @Override
  24. public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
  25. PrimitiveTypeWrapper integerWrapper = FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper();
  26. Field limit = new Field();
  27. limit.setName("limit");
  28. limit.setVisibility(JavaVisibility.PRIVATE);
  29. limit.setType(integerWrapper);
  30. topLevelClass.addField(limit);
  31. Method setLimit = new Method();
  32. setLimit.setVisibility(JavaVisibility.PUBLIC);
  33. setLimit.setName("setLimit");
  34. setLimit.addParameter(new Parameter(integerWrapper, "limit"));
  35. setLimit.addBodyLine("this.limit = limit;");
  36. topLevelClass.addMethod(setLimit);
  37. Method getLimit = new Method();
  38. getLimit.setVisibility(JavaVisibility.PUBLIC);
  39. getLimit.setReturnType(integerWrapper);
  40. getLimit.setName("getLimit");
  41. getLimit.addBodyLine("return limit;");
  42. topLevelClass.addMethod(getLimit);
  43. Field offset = new Field();
  44. offset.setName("offset");
  45. offset.setVisibility(JavaVisibility.PRIVATE);
  46. offset.setType(integerWrapper);
  47. topLevelClass.addField(offset);
  48. Method setOffset = new Method();
  49. setOffset.setVisibility(JavaVisibility.PUBLIC);
  50. setOffset.setName("setOffset");
  51. setOffset.addParameter(new Parameter(integerWrapper, "offset"));
  52. setOffset.addBodyLine("this.offset = offset;");
  53. topLevelClass.addMethod(setOffset);
  54. Method getOffset = new Method();
  55. getOffset.setVisibility(JavaVisibility.PUBLIC);
  56. getOffset.setReturnType(integerWrapper);
  57. getOffset.setName("getOffset");
  58. getOffset.addBodyLine("return offset;");
  59. topLevelClass.addMethod(getOffset);
  60. return true;
  61. }
  62. /**
  63. * 为Mapper.xml的selectByExample添加limit
  64. */
  65. @Override
  66. public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element,
  67. IntrospectedTable introspectedTable) {
  68. XmlElement ifLimitNotNullElement = new XmlElement("if");
  69. ifLimitNotNullElement.addAttribute(new Attribute("test", "limit != null"));
  70. XmlElement ifOffsetNotNullElement = new XmlElement("if");
  71. ifOffsetNotNullElement.addAttribute(new Attribute("test", "offset != null"));
  72. ifOffsetNotNullElement.addElement(new TextElement("limit ${offset}, ${limit}"));
  73. ifLimitNotNullElement.addElement(ifOffsetNotNullElement);
  74. XmlElement ifOffsetNullElement = new XmlElement("if");
  75. ifOffsetNullElement.addAttribute(new Attribute("test", "offset == null"));
  76. ifOffsetNullElement.addElement(new TextElement("limit ${limit}"));
  77. ifLimitNotNullElement.addElement(ifOffsetNullElement);
  78. element.addElement(ifLimitNotNullElement);
  79. return true;
  80. }
  81. }

插件的使用

在MyBatis Generator配置文件中配置plugin: 

  1. <context id="mysqlgenerator" targetRuntime="MyBatis3">
  2. <plugin type="com.xxg.mybatis.plugins.MySQLLimitPlugin"></plugin>
  3. ...
  4. </context>

如果直接加上以上配置运行mvn mybatis-generator:generate肯定会出现找不到这个插件的错误:

java.lang.ClassNotFoundException: com.xxg.mybatis.plugins.MySQLLimitPlugin

为了方便大家的使用,我已经把插件打包上传到GitHub,可以在pom.xml直接依赖使用: 

  1. pluginRepositories>
  2. <pluginRepository>
  3. <id>mybatis-generator-limit-plugin-mvn-repo</id>
  4. <url>https://raw.github.com/wucao/mybatis-generator-limit-plugin/mvn-repo/</url>
  5. </pluginRepository>
  6. </pluginRepositories>
  7. <build>
  8. <plugins>
  9. <plugin>
  10. <groupId>org.mybatis.generator</groupId>
  11. <artifactId>mybatis-generator-maven-plugin</artifactId>
  12. <version>1.3.2</version>
  13. <dependencies>
  14. <dependency>
  15. <groupId>mysql</groupId>
  16. <artifactId>mysql-connector-java</artifactId>
  17. <version>5.1.34</version>
  18. </dependency>
  19. <dependency>
  20. <groupId>com.xxg</groupId>
  21. <artifactId>mybatis-generator-plugin</artifactId>
  22. <version>1.0.0</version>
  23. </dependency>
  24. </dependencies>
  25. <configuration>
  26. <overwrite>true</overwrite>
  27. </configuration>
  28. </plugin>
  29. </plugins>
  30. </build>

此时运行mvn mybatis-generator:generate命令可以成功生成代码。

使用生成的代码分页

  1. xxExample example = new XxxExample();
  2. ...
  3. example.setLimit(10); // page size limit
  4. example.setOffset(20); // offset
  5. List<Xxx> list = xxxMapper.selectByExample(example);

以上代码运行时执行的SQL是:select ... limit 20, 10

  1. XxxExample example = new XxxExample();
  2. ...
  3. example.setLimit(10); // limit
  4. List<Xxx> list = xxxMapper.selectByExample(example);

以上代码运行时执行的SQL是:select ... limit 10

 

原文链接:http://www.cnblogs.com/zouwangblog/p/10979179.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号