博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Mybatias实现物理分页
阅读量:4041 次
发布时间:2019-05-24

本文共 5153 字,大约阅读时间需要 17 分钟。

Mybatis分页插件请使用这位帅哥开发的, 看起来不错. 

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值

完整代码请用svn从下面链接检出查看:

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

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

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

mysql

 

这个问题是org.mybatis.spring.SqlSessionFactoryBean这个代码里有个bug(244行,或者不是bug,是作者不想这么做法),如果感兴趣可以看下源码。配置文件做下如下修改:

 

Mybatis_Configuration.xml的配置如下:

1 
2 5
6 7   
8     
9   
10 11

 

转载地址:http://www.cnblogs.com/jcli/archive/2011/08/09/2132222.html

你可能感兴趣的文章
Yotta企业云盘助力科技行业创高峰
查看>>
Yotta企业云盘更好地为教育行业服务
查看>>
Yotta企业云盘怎么帮助到能源化工行业
查看>>
企业云盘如何助力商业新发展
查看>>
医疗行业运用企业云盘可以带来什么样的提升
查看>>
教育数字智能化能为现有体系带来新的起点
查看>>
媒体广告业如何将内容资产进行高效地综合管理与利用
查看>>
能源化工要怎么管控核心数据
查看>>
制药医疗使用云盘能带来什么样的好处
查看>>
媒体广告业如何运用云盘提升效率
查看>>
企业如何运用企业云盘进行数字化转型-实现新发展
查看>>
司法如何运用电子智能化加快现代化建设
查看>>
设计行业运用企业云盘能带来什么样的变化
查看>>
如何运用企业云盘助力企业数字化新发展
查看>>
企业云盘可以在哪些行业发光发热
查看>>
为什么汽车制造业需要企业云盘
查看>>
企业云盘和旅游行业碰撞在一起会产生怎样的火花
查看>>
医疗制药企业要怎么进一步进行系统的管理
查看>>
企业云盘如何让能源电力行业乘上数字化发展列车
查看>>
企业云盘为什么说是互联网软件公司的好帮手
查看>>