2 Star 0 Fork 0

舞尖芭蕾/mybatis-pagination

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

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

空文件

简介

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

发行版

暂无发行版

贡献者

全部

近期动态

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

搜索帮助