2 Star 0 Fork 0

舞尖芭蕾/mybatis-pagination

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
10年前
10年前
Loading...
README
MIT

MyBatis 分页插件


mybatis-pagination 是一个简易的MyBatis物理分页插件,使用org.apache.ibatis.session.RowBounds及其子类作为分页参数,禁用MyBatis自带的内存分页。

分页原理

简单来说就是通过拦截StatementHandler重写sql语句,实现数据库的物理分页

如何使用分页插件

单独使用 MyBatis

若是单独使用 MyBatis ,则需要在 mybatis 配置文件中配置插件 mybatis-configuration.xml

	<plugins>
	    <!-- 
	     | 分页插件配置 
	     | 插件首先会根据方言查找实现类,如果未找到则使用自定义的实现类,两者均为配置则抛出异常
	     | dialectType 数据库方言  
	     |             默认支持  mysql|oracle
	     | dialectClazz 方言实现类
	     |              自定义需要实现 net.oschina.archx.mybatis.IDialect 接口
	     | -->
	    <plugin interceptor="net.oschina.archx.mybatis.plugins.PaginationInterceptor">
	        <property name="dialectType" value="mysql" />
	        <property name="dialectClazz" value="net.oschina.archx.mybatis.dialect.MySqlDialect" />
	    </plugin>
	</plugins>

与 Spring 集成

在与 Spring 框架集成使用 MyBatis 时,插件配置在 SqlSessionFactoryBean 的属性中 spring-mybatis.xml

    <!-- MyBatis SqlSessionFactoryBean 配置 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="plugins">
            <array>
                <!-- 
                 | 分页插件配置 
                 | 插件首先会根据方言查找实现类,如果未找到则使用自定义的实现类,两者均为配置则抛出异常
                 | dialectType 数据库方言  
                 |             默认支持  mysql|oracle
                 | dialectClazz 方言实现类
                 |              自定义需要实现 net.oschina.archx.mybatis.IDialect 接口
                 | -->
                <bean id="paginationInterceptor" class="net.oschina.archx.mybatis.plugins.PaginationInterceptor">
                    <property name="dialectType" value="mysql" />
                    <property name="dialectClazz" value="net.oschina.archx.mybatis.dialect.MySqlDialect" />
                </bean>
            </array>
        </property>
    </bean>

如何分页

使用org.apache.ibatis.session.RowBounds及其子类作为分页参数将触发分页插件,插件提供一个简易的分页模型 net.oschina.archx.mybatis.Pagination,可以使用其作为分页参数。

分页模型

参照 net.oschina.archx.mybatis.Pagination.java 分页模型,提供两个构造函数

Pagination(offset, limit) 偏移量, 界限

Paginaiton(current, size, total) 当前页,每页显示记录,总记录数 自动计算偏移量和界限

演示代码

  1. 实体类 net.oschina.archx.mybatis.bean.Message.java
    public class Message {
        private long mid;
    	private String message;
        ...
    }
  1. 定义 Mapper 接口 net.oschina.archx.mybatis.mapper.MessageMapper.java
    public interface MessageMapper {
    	/**
    	 * 消息列表
    	 * 
    	 * @return
    	 */
    	List<Message> list();
    
    	/**
    	 * 消息列表 分页显示
    	 * 
    	 * @param pagination
    	 * @return
    	 */
    	List<Message> list(RowBounds pagination);
    }
  1. mapper.xml 配置,namespace 必须和接口完整名称一致 Message-mapper.xml
    <?xml version="1.0" encoding="UTF-8" ?>  
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!--NAMESPACE 必须和接口的类路径一样 -->
    <mapper namespace="net.oschina.archx.mybatis.mapper.MessageMapper">
        <!-- 是否支持重载呢?  -->
        <select id="list" resultType="Message">
            select * from tb_message
        </select>
    </mapper>

调用方式

参照 net.oschina.archx.mybatis.test.MyBatisJUnitTest.java 测试用例

    @Test
    public void unknowTotalRecords() {
        System.out.println("[测试未知总记录条数分页]");
        SqlSession session = sqlSessionFactory.openSession();
        MessageMapper mapper = session.getMapper(MessageMapper.class);
        // 查询从第 1 开始一共 4 条数据, MySql limit 从 0 开始

        // 返回 2 - 5 的记录

        Pagination pagination = new Pagination(1, 4);
        List<Message> list = mapper.list(pagination);
        // 返回查询总记录条数

        System.out.println("total : " + pagination.getTotal());
        print(list, "Pagination(1, 4)");
        Assert.assertTrue(list != null && list.size() == 4);
    }

    @Test
    public void clearTotalRecords() {
        System.out.println("[测试已知总记录条数分页]");
        SqlSession session = sqlSessionFactory.openSession();
        MessageMapper mapper = session.getMapper(MessageMapper.class);
        // 测试数据 188 条,每页显示15条,查询第2页数据

        // 返回 16 - 30 的记录

        Pagination pagination = new Pagination(2, 15, 188);
        List<Message> list = mapper.list(pagination);
        print(list, "Pagination(2,15,188)");
        Assert.assertTrue(list != null && list.size() == 15);
    }

MyBatis 配置文件说明

配置文件结构

configuration

properties 属性定义配置

settings 全局配置设置

typeAliases 别名定义

typeHandlers 类型处理器配置

objectFactory 对象工厂

plugins 插件配置

environments 环境配置

environment

transactionManager 事务管理器

dataSource 数据源

mappers 映射定义

属性定义配置

加载配置文件 resource="jdbc.properties" 可以在本配置文件中使用 ${name} 来使用属性值

可通 <property name="name" value="value"/>方式定义属性, 加载的配置文件中的属性会覆盖掉此处定义的同名属性

<properties resource="jdbc.properties">
    <property name="" value=""/>
</properties>

全局配置设置

可配置选项 默认值, 描述

  • aggressiveLazyLoading true, 当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。
  • multipleResultSetsEnabled true, 允许和不允许单条语句返回多个数据集(取决于驱动需求)
  • useColumnLabel true, 使用列标签代替列名称。不同的驱动器有不同的作法。参考一下驱动器文档,或者用这两个不同的选项进行测试一下。
  • useGeneratedKeys false, 允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。
  • autoMappingBehavior PARTIAL, 指定MyBatis 是否并且如何来自动映射数据表字段与对象的属性。PARTIAL将只自动映射简单的,没有嵌套的结果。FULL 将自动映射所有复杂的结果。
  • defaultExecutorType SIMPLE, 配置和设定执行器,SIMPLE 执行器执行其它语句。REUSE 执行器可能重复使用prepared statements 语句,BATCH执行器可以重复执行语句和批量更新。
  • defaultStatementTimeout null, 设置一个时限,以决定让驱动器等待数据库回应的多长时间为超时
<settings>
    <!-- 这个配置使全局的映射器启用或禁用缓存 -->
    <setting name="cacheEnabled" value="true" />
    <!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载 -->
    <setting name="lazyLoadingEnabled" value="true" />
</settings>

别名定义

明确定义

<typeAlias type="net.oschina.archx.mybatis.bean.Message" alias="Message" />

扫描指定包下的实体

<package name="net.oschina.archx.mybatis.model" />

<typeAliases>
    <package name="net.oschina.archx.mybatis.model" />
    <package name="net.oschina.archx.mybatis.bean" />
</typeAliases>

类型处理器配置

明确指定

<typeHandler handler="net.oschina.archx.mybatis.handler.EmployeeGenderTypeHandler" javaType="" jdbcType=""/>

扫描指定包

<package name="net.oschina.archx.mybatis.handler" />

<typeHandlers>
    <!-- 
     | 使用以下两个注解标识 java类型 和 jdbc类型 以后就无需配置 javaType="" jdbcType=""两个属性
     |
     | @MappedTypes({Employee.Gender.class})
     | @MappedJdbcTypes({JdbcType.VARCHAR}) 
     | -->
    <typeHandler handler="net.oschina.archx.mybatis.handler.EmployeeGenderTypeHandler" />
</typeHandlers>

插件配置

<plugins>
    <!-- 
     | 分页插件配置 
     | 插件首先会根据方言查找实现类,如果未找到则使用自定义的实现类,两者均为配置则抛出异常
     | dialectType 数据库方言  
     |             默认支持  mysql|oracle
     | dialectClazz 方言实现类
     |              自定义需要实现 net.oschina.archx.mybatis.IDialect 接口
     | -->
    <plugin interceptor="net.oschina.archx.mybatis.plugins.PaginationInterceptor">
        <property name="dialectType" value="mysql" />
        <property name="dialectClazz" value="net.oschina.archx.mybatis.dialect.MySqlDialect" />
    </plugin>
</plugins>

环境配置

<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC">
            <property name="" value="" />
        </transactionManager>
        <dataSource type="UNPOOLED">
            <property name="driver" value="${jdbc.driver}" />
            <property name="url" value="${jdbc.url}" />
            <property name="username" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
        </dataSource>
    </environment>
</environments>

映射定义

<!--
 | SQL映射定义Mappers
 |
 | resource 指定在classpath中的mapper文件。
 | url      通过完全文件系统路径或者web URL地址来指向mapper文件
 | class    指向一个mapper接口
 | package  指向可以找到Mapper接口的包名
 | -->
<mappers>
    <mapper resource="mapper/Message-mapper.xml" />
    <mapper resource="mapper/Employee-mapper.xml" />
</mappers>

自定义类型处理器的使用场景

一个雇员实体类的结构如下, 使用一个自定义枚举类型 Gender来限定雇员的性别输入

public class Employee {
    private Long id;
    private String name;
    private Integer age;
    private Gender gender = Gender.Male;

    public static enum Gender {
        Male("男人"), Femal("女人");

        private final String info;

        private Gender(String info) {
            this.info = info;
        }

        public String getInfo() {
            return info;
        }
    }
    ...
}

自定义EmployeeGenderTypeHandler 来处理 Gender类型,使我们在存储到数据库时使用 MaleFemal字符串,从数据查询时将字符串转换为 Employee.Gender 枚举类型

/**
 * 雇员性别枚举类型处理器
 * 
 * @author ArchX[archx@foxmail.com]
 */
@MappedTypes({Employee.Gender.class})
@MappedJdbcTypes({JdbcType.VARCHAR})
public class EmployeeGenderTypeHandler extends BaseTypeHandler<Employee.Gender> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Gender parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter.name());
    }

    @Override
    public Gender getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return getGender(rs.getString(columnName));
    }

    @Override
    public Gender getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return getGender(rs.getString(columnIndex));
    }

    @Override
    public Gender getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return getGender(cs.getString(columnIndex));
    }

    private Gender getGender(String value) {
        if (value == null)
            return null;
        try {
            return Gender.valueOf(value);
        } catch (IllegalArgumentException e) {
            return null;
        }
    }
}

关联查询应用场景

雇员的报告 Report 实体中包含有雇员 Employee 和 报告的评论信息 List<Comment>,在查询报告的同时需要关联查询出雇员和评论信息

报告实体

public class Report {
    private Integer rid;
    private String content;
    private Employee employee; // 所属雇员
    private List<Comment> comments; // 评论信息
    ....
}

Report-mapper.xml 配置

	<!--NAMESPACE 必须和接口的类路径一样 -->
	<mapper namespace="net.oschina.archx.mybatis.mapper.ReportMapper">
	
	    <resultMap type="Report" id="reportMap">
	        <id column="rid" property="rid" />
	        <result column="content" property="content" />
	        <!-- 
	         | 会造成N+1问题
	         | <association property="employee" column="eid" javaType="Employee" select="employees" />
	         | -->
	        <association property="employee" javaType="Employee">
	            <id column="id" property="id"/>
	            <result column="name" property="name"/>
	            <result column="age" property="age"/>
	            <result column="gender" property="gender"/>
	        </association>
	        <collection property="comments" column="rid" ofType="Comment" select="comments" />
	    </resultMap>
	
	    <!-- 查询所有报告 -->
	    <select id="list" resultMap="reportMap">
	        select r.*, e.* from tb_report r left join tb_employee e on r.eid = e.id
	    </select>
	    
	    <!-- 查询所有评论 -->
	    <select id="comments" parameterType="int" resultType="Comment">
	        select * from tb_comment where rid = #{rid}
	    </select>
	</mapper>

测试结果

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running net.oschina.archx.mybatis.test.MyBatisJUnitTest
[测试未知总记录条数分页]
total : 188
Pagination(1, 4) > { "mid":2,"message":"message > 2" }
Pagination(1, 4) > { "mid":3,"message":"message > 3" }
Pagination(1, 4) > { "mid":4,"message":"message > 4" }
Pagination(1, 4) > { "mid":5,"message":"message > 5" }
=============================================================
[测试创建评论]
true
[测试报告关联查询]
 employee : 似玉 > 男人
 report : 今年的年终奖呢
 comments : 
 	 -> 你是猴子请来的逗比么?
 	 -> 还想不想干了?
 	 -> 233333

 employee : 如花 > 女人
 report : 报告老板
 comments : 
 	 -> 233333
 	 -> 有事说事

[测试已知总记录条数分页]
Pagination(2,15,188) > { "mid":16,"message":"message > 16" }
Pagination(2,15,188) > { "mid":17,"message":"message > 17" }
Pagination(2,15,188) > { "mid":18,"message":"message > 18" }
Pagination(2,15,188) > { "mid":19,"message":"message > 19" }
Pagination(2,15,188) > { "mid":20,"message":"message > 20" }
Pagination(2,15,188) > { "mid":21,"message":"message > 21" }
Pagination(2,15,188) > { "mid":22,"message":"message > 22" }
Pagination(2,15,188) > { "mid":23,"message":"message > 23" }
Pagination(2,15,188) > { "mid":24,"message":"message > 24" }
Pagination(2,15,188) > { "mid":25,"message":"message > 25" }
Pagination(2,15,188) > { "mid":26,"message":"message > 26" }
Pagination(2,15,188) > { "mid":27,"message":"message > 27" }
Pagination(2,15,188) > { "mid":28,"message":"message > 28" }
Pagination(2,15,188) > { "mid":29,"message":"message > 29" }
Pagination(2,15,188) > { "mid":30,"message":"message > 30" }
=============================================================
[测试创建雇员]
true
Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.213 sec

Results :

Tests run: 5, Failures: 0, Errors: 0, Skipped: 0

源码包含测试用例,更多细节请查看源码

The MIT License (MIT) Copyright (c) 2015 Archx Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

MyBatis 简易分页插件 展开 收起
README
MIT
取消

发行版

暂无发行版

贡献者 (1)

全部

近期动态

不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/wangdanqing/mybatis-pagination.git
git@gitee.com:wangdanqing/mybatis-pagination.git
wangdanqing
mybatis-pagination
mybatis-pagination
master

搜索帮助