`

mybatis高级应用系列一:分页功能

阅读更多

转载自【海鸟】的博客:http://www.cnblogs.com/jcli/archive/2011/08/09/2132222.html

 

 

Mybatis3.0出来已有段时间了,其实自己挺喜欢这样的一个持久化框架的,因为它简单实用,学习成本低。Mybatis3.0在整体结构上和ibatis2.X差不多,改进特性如下:

1.         解析xml引进了Xpath,不像ibatis2.x那样业余

2.         动态sqlOGNL解析

3.         加入注解配置sql,感觉没什么特别大的用途,我更喜欢xml方式,代码和配置分离,这也是ibatis的初衷

4.         加强了缓存这块的功能。Mybatis3.0把缓存模块分得更细,分为“持久实现(prepetual)”和“资源回收策略实现(eviction)”,更好的对缓存功能进行自己组合和扩展

5.         终于加入的plugin功能,就像struts一样,这样就可以很好的扩展内部的Executor,StatementHandler….等内部对象功能。

 

一下只能想到这些了,总之改动后的代码结构清晰多了,如果各位看下源码的话,也是学习设计模式很好的课件,里面的代码用到了很多经典的设计模式,这在之后的系列学习中会讲到。

 

这一篇文章讲下分页的功能。

 

正如和ibatis以前的版本一样,mybatis的分页还是基于内存分页(查找出所有记录再取出偏移量的记录,如果jdbc驱支持absolute定位或者rs.next()到指定偏移位置),其实这样的分页实现基本没用,特别是大量数据情况下。

 

要想改变mybatis内部的分页行为,理论上只要把最终要执行的sql转变成对应的分页语句就行了。首先,我们熟悉下mybatis内部执行查询的动态交互图:

 

可以很清楚的看到,真正生成Statement并执行sql的语句是StatementHandler接口的某个实现,这样就可以写个插件对StatementHandler的行为进行拦截。

 

package study.mybatis.interceptor;

import java.sql.Connection;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;
import study.mybatis.dialect.Dialect;
import study.mybatis.dialect.MySql5Dialect;

@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class})})

publicclass PaginationInterceptor implements Interceptor{

    privatefinalstatic Log log = LogFactory.getLog(PaginationInterceptor.class);

   

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
       StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
       BoundSql boundSql = statementHandler.getBoundSql();
       MetaObject metaStatementHandler = MetaObject.forObject(statementHandler);
       RowBounds rowBounds = (RowBounds)metaStatementHandler.getValue("delegate.rowBounds");
       if(rowBounds ==null|| rowBounds == RowBounds.DEFAULT){
           return invocation.proceed();
       }
       Configuration configuration = (Configuration)metaStatementHandler.getValue("delegate.configuration");
       Dialect.Type databaseType  =null;
       try{
           databaseType = Dialect.Type.valueOf(configuration.getVariables().getProperty("dialect").toUpperCase());
       } catch(Exception e){
           //ignore
       }
       if(databaseType ==null){
           thrownew RuntimeException("the value of the dialect property in configuration.xml is not defined : "+ configuration.getVariables().getProperty("dialect"));
       }
       Dialect dialect =null;
       switch(databaseType){
           case MYSQL:
              dialect =new MySql5Dialect(); 
       }

       String originalSql = (String)metaStatementHandler.getValue("delegate.boundSql.sql");
       metaStatementHandler.setValue("delegate.boundSql.sql", dialect.getLimitString(originalSql, rowBounds.getOffset(), rowBounds.getLimit()) );
       metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET );
       metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT );
       if(log.isDebugEnabled()){
           log.debug("生成分页SQL : "+ boundSql.getSql());
       }
       return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
       return Plugin.wrap(target, this);
    }

    @Override
    publicvoid setProperties(Properties properties) {
    }
}

里面最重要的三条语句:

metaStatementHandler.setValue("delegate.boundSql.sql", dialect.getLimitString(originalSql, rowBounds.getOffset(), rowBounds.getLimit()) );

metaStatementHandler.setValue(
"delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET );

metaStatementHandler.setValue(
"delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT );                                          
改别要执行的sql语句,现在新设置的sql语句是物理分页的,所以现在不再需要mybatis进行额外的操作了,所以把rowBounds的偏移量恢复为初始值(offet:0,limit:Integer.max) 为了指定数据库版本,在mybatis全局配置文件设置dialect值
  
<properties>
    <property name="dialect" value="mysql"/>
</properties>
<plugins>
<plugin interceptor="study.mybatis.interceptor.PaginationInterceptor">
    </plugin>
</plugins>
 完整代码请用svn从下面链接检出查看:

 

svn checkout http://20110311start.googlecode.com/svn/trunk/

下个系列将会讲下缓存的扩展应用。    
-----------------------------分隔线---------------------------------------------

最近有朋友用mybatis和spring整合的时候如果按照下列方式发现dialect属性不能设置成功:

 

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="typeAliasesPackage" value="com.***.web.domain" />
    <property name="plugins">
        <array>
            <ref bean="paginationInterceptor"/>
        </array>
    </property>
    <property name="configurationProperties">
        <props>
            <prop key="dialect">mysql</prop>
        </props>
    </property>
</bean>
 

 

这个问题是org.mybatis.spring.SqlSessionFactoryBean这个代码里有个bug(244行,或者不是bug,是作者不想这么做法),如果感兴趣可以看下源码。配置文件做下如下修改:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="typeAliasesPackage" value="com.***.web.domain" />
    <property name="plugins">
        <array>
            <ref bean="paginationInterceptor"/>
        </array>
    </property>
    <!-- 这里不要,注释掉
    <property name="configurationProperties">
        <props>
            <prop key="dialect">mysql</prop>
        </props>
    </property>
    -->
    <!--  加上这个属性 -->
    <property name="configLocation" value="classpath:Mybatis_Configuration.xml"/>
</bean>
 Mybatis_Configuration.xml的配置如下:
<?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
 <configuration>
   <properties>
     <property name="dialect" value="oracle"/>
   </properties>
 </configuration>
 

 

分享到:
评论

相关推荐

    MyBatis高级应用:实现自定义分页插件

    MyBatis 是一个流行的 Java 持久层框架,它提供了简单而强大的数据库操作能力。在处理大量数据时,分页功能...通过本文的学习,读者应该能够掌握在 MyBatis 中实现自定义分页插件的方法,并能够将其应用到实际项目中。

    mybatis分页完整的项目

    【标题】"mybatis分页完整的项目"是一个涵盖了MyBatis分页功能的完整Java Web项目,旨在帮助开发者理解和实现MyBatis在实际应用中的分页处理。该项目结合了Spring和MyBatis两大流行框架,提供了从数据库查询数据并...

    mybatis分页插件代码

    【标题】"mybatis分页插件代码"主要涉及到MyBatis框架中的一种增强功能——分页插件的使用。MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。在处理大数据量时,分页查询是必不可少的优化...

    mybatis+bootstarp+pageHelper实现分页.rar

    在IT行业中,分页是网页应用中不可或缺的功能,它能够帮助用户更有效地浏览大量数据,避免一次性加载所有信息导致页面加载缓慢。本项目是关于如何使用MyBatis、Bootstrap和PageHelper来实现一个高效的分页功能。下面...

    mybatis数据库分页Spring原生例子

    在本文中,我们将深入探讨如何在Spring框架中结合MyBatis实现数据库的分页功能。MyBatis是一个优秀的持久层...通过上述步骤,你可以有效地在Spring应用中实现MyBatis的分页功能,为你的项目增添更多灵活性和可扩展性。

    MyBatis 分页

    此外,MyBatis的分页插件通常还会提供其他高级功能,比如统计总记录数、自定义分页参数等。这些功能使得在开发过程中能够更加便捷地处理分页问题,提升开发效率。 在实际使用中,应根据项目需求和数据库类型选择...

    MyBatis分页

    《MyBatis分页详解与实战应用》 在现代Web开发中,数据的分页展示是必不可少的功能,尤其是在处理大量数据时,为了提高用户体验和优化性能,MyBatis提供了强大的分页支持。本文将深入探讨MyBatis的分页原理,并结合...

    ajax+jso+mybatis+mysql模仿百度简单分页案例

    在本案例中,我们主要探讨如何使用Ajax、JSON、MyBatis和MySQL来实现一个类似于百度的简单分页功能。这个教程特别适合那些希望提升自己技能的程序员,通过阅读源代码和注释,你可以深入理解这些技术的结合使用。下面...

    SpringMVC+mybatis 增删改查,分页maven版

    2. **MyBatis**:MyBatis是一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的XML或注解进行配置和原始映射,将...

    mybatis-plus分页查询 学习mybatis-plus在项目中的简单使用,代码生成器,分页查询,多数据源等

    MyBatis-Plus是一个强大的MyBatis扩展工具,它在MyBatis的基础上简化了许多操作,提供了包括但不限于自动装填实体类、代码生成器、分页查询等功能,使得开发者能够更高效地进行Java开发。本篇将详细介绍MyBatis-Plus...

    Mybatis插件下 的分页查询

    PageHelper是Mybatis的一个强大插件,它实现了对数据库的分页查询功能,使得在处理大数据量时能有效地提高性能并优化用户体验。 首先,我们来理解一下分页查询的基本概念。分页查询是指在数据量较大的情况下,将...

    springboot+mybatis拦截器实现自动分页

    本教程将详细讲解如何利用拦截器来实现这一功能。 首先,我们需要理解Spring Boot和MyBatis的基础。Spring Boot简化了Spring应用程序的开发过程,它提供了预配置的依赖项、内嵌的HTTP服务器(如Tomcat)以及自动...

    mybatis 分页插件jar包

    MyBatis分页插件是Java开发中一个非常实用的工具,主要针对MyBatis框架进行扩展,以方便开发者在处理大量数据时实现高效的分页功能。标题中的"mybatis 分页插件jar包"指的是这个插件的可执行文件形式,即Java的JAR...

    MyBatis 最简单的分页

    分页是Web应用程序中非常常见的一种功能,它能够帮助用户更有效地浏览大量数据,避免一次性加载过多信息导致页面响应变慢或内存压力过大。 MyBatis 是一个轻量级的ORM(对象关系映射)框架,它允许开发者通过编写...

    MyBatis拦截器分页与动态修改SQL及其参数值

    MyBatis是一个强大的Java持久层框架,它允许开发者将数据库操作与业务逻辑分离,通过XML或注解方式...通过分析提供的代码文件,我们可以深入学习MyBatis的高级特性,并将其应用到实际项目中,提升开发效率和代码质量。

    三,MyBatis动态SQL,缓存和分页插件, Lombok工具

    MyBatis提供了两级缓存:一级缓存默认存在于SqlSession级别,同一个SqlSession内的多次相同查询会直接从缓存获取结果;二级缓存则可跨SqlSession,它是基于namespace的,需要在配置文件中开启,并在Mapper接口或XML...

    Mybatis-Servelt+JSP+Mybatis 分页实战(取PageInfo的属性完成).zip

    【标题】 "Mybatis-Servelt+JSP+Mybatis 分页实战(取PageInfo的属性完成)" 提供了一个实际的开发案例,演示了如何在Java Web应用中使用Mybatis框架进行分页处理。这个实战项目的核心是整合Servlet、JSP和Mybatis,...

    mybatis分页插件源码

    MyBatis 分页插件是数据库操作中常用的一个工具,它极大地简化了在MyBatis框架下实现分页查询的工作。这个源码分享主要针对MySQL和Oracle两大主流数据库,为开发者提供了高效且易于使用的分页解决方案。下面我们将...

    mybatis基础分页,高级查询

    分页查询是大型应用必备的功能,MyBatis 提供了两种常见的分页方式:一是通过自定义插件(Interceptor),二是使用 MyBatis 提供的 PageHelper 插件。在本项目中,标签提及了 "interceptor",这可能意味着自定义拦截...

    mybatis的分页插件

    总的来说,MyBatis 分页插件 PageHelper 是一个强大且易于使用的工具,它能够帮助开发者快速实现分页功能,提高开发效率,同时提供了一定的性能优化。无论是在小型项目还是大型项目中,它都是一个值得信赖的伙伴。

Global site tag (gtag.js) - Google Analytics