badqiu

XPer
随笔 - 46, 文章 - 3, 评论 - 195, 引用 - 0
数据加载中……

ibatis3基于方言的分页

(注:以下代码是基于ibatis3 beta4的扩展,ibatis3正式版如果实现改变,将会继续跟进修改)

 

 

iBatis3默认使用的分页是基于游标的分页,而这种分页在不同的数据库上性能差异不一致,最好的办法当然是使用类似hibernate的基于方言(Dialect)的物理分页功能。

iBatis3现在提供插件功能,通过插件我们可以编写自己的拦截器来拦截iBatis3的主要执行方法来完成相关功能的扩展。

 

 

 

能够拦截的的类如下:

 

Java代码 
  1. Executor  
  2.     (update,query,flushStatements,commit,rollback,getTransaction,close,isClosed)  
  3. ParameterHandler  
  4.     (getParameterObject,setParameters)  
  5. ResultSetHandler  
  6.     (handleResultSets,handleOutputParameters)  
  7. StatementHandler  
  8.     (prepare,parameterize,batch,update,query)  

 

 但此次我们感兴趣的是Executor.query()方法,查询方法最终都是执行该方法。

该方法完整是:

 

Java代码 
  1. Executor.query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException;  

 

 

分页方言的基本实现:

以Mysql数据库示例,即有一个方法 query(sql,offset,limit);

 

 

Java代码 
  1. query("select * from user",5,10);  
 

 

经过我们的拦截器拦截处理,变成

 

Java代码 
  1. query("select * from user limit 5,10",0,0);  
 

 

1.拦截类实现:

 

Java代码 
  1. @Intercepts({@Signature(  
  2.         type= Executor.class,  
  3.         method = "query",  
  4.         args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})  
  5. public class OffsetLimitInterceptor implements Interceptor{  
  6.     static int MAPPED_STATEMENT_INDEX = 0;  
  7.     static int PARAMETER_INDEX = 1;  
  8.     static int ROWBOUNDS_INDEX = 2;  
  9.     static int RESULT_HANDLER_INDEX = 3;  
  10.       
  11.     Dialect dialect;  
  12.       
  13.     public Object intercept(Invocation invocation) throws Throwable {  
  14.         processIntercept(invocation.getArgs());  
  15.         return invocation.proceed();  
  16.     }  
  17.   
  18.     void processIntercept(final Object[] queryArgs) {  
  19.         //queryArgs = query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler)  
  20.         MappedStatement ms = (MappedStatement)queryArgs[MAPPED_STATEMENT_INDEX];  
  21.         Object parameter = queryArgs[PARAMETER_INDEX];  
  22.         final RowBounds rowBounds = (RowBounds)queryArgs[ROWBOUNDS_INDEX];  
  23.         int offset = rowBounds.getOffset();  
  24.         int limit = rowBounds.getLimit();  
  25.           
  26.         if(dialect.supportsLimit() && (offset != RowBounds.NO_ROW_OFFSET || limit != RowBounds.NO_ROW_LIMIT)) {  
  27.             BoundSql boundSql = ms.getBoundSql(parameter);  
  28.             String sql = boundSql.getSql().trim();  
  29.             if (dialect.supportsLimitOffset()) {  
  30.                 sql = dialect.getLimitString(sql, offset, limit);  
  31.                 offset = RowBounds.NO_ROW_OFFSET;  
  32.             } else {  
  33.                 sql = dialect.getLimitString(sql, 0, limit);  
  34.             }  
  35.             limit = RowBounds.NO_ROW_LIMIT;  
  36.               
  37.             queryArgs[ROWBOUNDS_INDEX] = new RowBounds(offset,limit);  
  38.             BoundSql newBoundSql = new BoundSql(sql, boundSql.getParameterMappings(), boundSql.getParameterObject());  
  39.             MappedStatement newMs = copyFromMappedStatement(ms, new BoundSqlSqlSource(newBoundSql));  
  40.             queryArgs[MAPPED_STATEMENT_INDEX] = newMs;  
  41.         }  
  42.     }  
  43.       
  44.     private MappedStatement copyFromMappedStatement(MappedStatement ms,SqlSource newSqlSource) {  
  45.         Builder builder = new MappedStatement.Builder(ms.getConfiguration(),ms.getId(),newSqlSource,ms.getSqlCommandType());  
  46.         builder.resource(ms.getResource());  
  47.         builder.fetchSize(ms.getFetchSize());  
  48.         builder.statementType(ms.getStatementType());  
  49.         builder.keyGenerator(ms.getKeyGenerator());  
  50.         builder.keyProperty(ms.getKeyProperty());  
  51.         builder.timeout(ms.getTimeout());  
  52.         builder.parameterMap(ms.getParameterMap());  
  53.         builder.resultMaps(ms.getResultMaps());  
  54.         builder.cache(ms.getCache());  
  55.         MappedStatement newMs = builder.build();  
  56.         return newMs;  
  57.     }  
  58.   
  59.     public Object plugin(Object target) {  
  60.         return Plugin.wrap(target, this);  
  61.     }  
  62.   
  63.     public void setProperties(Properties properties) {  
  64.         String dialectClass = new PropertiesHelper(properties).getRequiredString("dialectClass");  
  65.         try {  
  66.             dialect = (Dialect)Class.forName(dialectClass).newInstance();  
  67.         } catch (Exception e) {  
  68.             throw new RuntimeException("cannot create dialect instance by dialectClass:"+dialectClass,e);  
  69.         }   
  70.         System.out.println(OffsetLimitInterceptor.class.getSimpleName()+".dialect="+dialectClass);  
  71.     }  
  72.       
  73.     public static class BoundSqlSqlSource implements SqlSource {  
  74.         BoundSql boundSql;  
  75.         public BoundSqlSqlSource(BoundSql boundSql) {  
  76.             this.boundSql = boundSql;  
  77.         }  
  78.         public BoundSql getBoundSql(Object parameterObject) {  
  79.             return boundSql;  
  80.         }  
  81.     }  
  82.       
  83. }  
 

 

2.ibatis3配置文件内容:

Xml代码 
  1. <configuration>  
  2.     <plugins>  
  3.         <!-- 指定数据库分页方言Dialect, 其它方言:OracleDialect,SQLServerDialect,SybaseDialect,DB2Dialect,PostgreSQLDialect,MySQLDialect,DerbyDialect-->  
  4.         <plugin interceptor="cn.org.rapid_framework.ibatis3.plugin.OffsetLimitInterceptor">  
  5.             <property name="dialectClass" value="cn.org.rapid_framework.jdbc.dialect.MySQLDialect"/>  
  6.         </plugin>  
  7.     </plugins>  
  8.   
  9.     <environments default="development">  
  10.         <environment id="development">  
  11.             <transactionManager type="JDBC" />  
  12.             <dataSource type="POOLED">  
  13.                 <property name="driver" value="com.mysql.jdbc.Driver" />  
  14.                 <property name="url" value="jdbc:mysql://localhost:3306/test" />  
  15.                 <property name="username" value="root" />  
  16.                 <property name="password" value="123456" />  
  17.             </dataSource>  
  18.         </environment>  
  19.     </environments>  
  20.   
  21.     <mappers>  
  22.         <mapper resource="com/company/project/model/mapper/BlogMapper.xml" />  
  23.     </mappers>  
  24. </configuration>  
 

3.MysqlDialect实现

Java代码 
  1. public class MySQLDialect extends Dialect{  
  2.   
  3.     public boolean supportsLimitOffset(){  
  4.         return true;  
  5.     }  
  6.       
  7.     public boolean supportsLimit() {     
  8.         return true;     
  9.     }    
  10.       
  11.     public String getLimitString(String sql, int offset, int limit) {  
  12.             return getLimitString(sql,offset,String.valueOf(offset),limit,String.valueOf(limit));  
  13.     }  
  14.       
  15.     public String getLimitString(String sql, int offset,String offsetPlaceholder, int limit, String limitPlaceholder) {  
  16.         if (offset > 0) {     
  17.             return sql + " limit "+offsetPlaceholder+","+limitPlaceholder;   
  18.         } else {     
  19.             return sql + " limit "+limitPlaceholder;  
  20.         }    
  21.     }     
  22.     
  23. }  

 

其它数据库的Dialect实现请查看:

http://rapid-framework.googlecode.com/svn/trunk/rapid-framework/src/rapid_framework_common/cn/org/rapid_framework/jdbc/dialect/

 

4.分页使用

直接调用SqlSession.selectList(statement, parameter, new RowBounds(offset,limit))即可使用物理分页

 

5.存在的问题

现不是使用占位符的方式(即不是“limit ?,?”而是使用“limit 8,20”)使用分页

 

完整代码可以查看即将发布的rapid-framework 3.0的ibatis3插件

 

posted on 2009-10-20 09:04 badqiu 阅读(3945) 评论(5)  编辑  收藏

评论

# re: ibatis3基于方言的分页  回复  更多评论   

sqlserver2000怎么办,oracle怎么办,db2怎么办。。。mysql分页是最简单的数据库了。
2009-11-01 18:10 | spingNo1

# re: ibatis3基于方言的分页[未登录]  回复  更多评论   

问这个问题前请先仔细再看一下文章内容.
2009-11-01 19:02 | badqiu

# re: ibatis3基于方言的分页  回复  更多评论   

rapid-framework 3.0的ibatis3插件不错
2009-12-17 14:07 | 团派家园

# re: ibatis3基于方言的分页  回复  更多评论   

rapid-framework 好东西啊
2010-06-04 10:38 | king2ksu

# re: ibatis3基于方言的分页  回复  更多评论   

BoundSql newBoundSql = new BoundSql(sql, boundSql.getParameterMappings(), boundSql.getParameterObject());
有错因为BoundSql的构造函数如下,少传了configuration,应该怎么改呀
public BoundSql(Configuration configuration, String sql, List parameterMappings, Object parameterObject)

2011-06-16 17:40 | wypsmall

只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问