文档章节

简单实现ibatis的物理分页

微凉的风
 微凉的风
发布于 2012/04/05 11:38
字数 680
阅读 2762
收藏 5

本文是原创文章,转载请注明出处:http://my.oschina.net/fqt/blog/52431

一直以来ibatis的分页都是通过滚动ResultSet实现的,应该算是逻辑分页吧。逻辑分页虽然能很干净地独立于特定数据库,但效率在多数情况下不及特定数据库支持的物理分页,而hibernate的分页则是直接组装sql,充分利用了特定数据库的分页机制,效率相对较高。

网上已有《使ibatis支持hibernate式的物理分页》等类似的文章以继承SqlExecutor的方式实现了物理分页,但是侵入性非常强,还得实现数据库方言,方法非常复杂。同时SqlExecutor不是接口,对它的方法继承也不能保证版本稳定。本文中将介绍的方式是实现queryWithSqlHandler方法,在查询前将通过SqlHandler接口把sql传给调用者,再用处理后的sql进行最终查询,从而实现物理分页等功能:

//用queryWithSqlHandler方法实现物理分页的例子:
public Page queryPage(String statementId, param, final Page page){
	final int pageNum = page.getPageNum();
	final int pageSize = page.getPageSize();
	List list = queryWithSqlHandler(statementId, param, new SqlHandler() {
					@Override
					public String handle(String sql, Object[] params) throws SQLException {
						//查询总记录数
						int total = getJdbcTemplate().queryForInt("select count(1) as RECORDS from (" + sql + ")", params);
						page.setTotal(total);
						//返回经过分页包装后的Sql
						return "select * from (select row_.*, rownum row_num_ from ("+sql+") row_ where rownum<="+ pageNum*pageSize +") where row_num_ > "+ (pageNum-1)*pageSize;
					}
				});
	page.setRows(list);
	return page;
}

我们来看queryWithSqlHandler方法的实现:

/**
 * 提供查询前对sql处理的功能
 *
 * @param statementId
 * @param param
 * @param sqlHandler sql处理器
 * @return
 */
private List queryWithSqlHandler(final String statementId, final Object param, final SqlHandler sqlHandler) {
	final SqlMapClientImpl smc = getSqlMapClient();
	if (sqlHandler != null) {
		final MappedStatement mappedStatement = smc.getMappedStatement(statementId);
		final Sql dySql = mappedStatement.getSql();
		if (Proxy.isProxyClass(dySql.getClass())) {
			log.debug("该Sql对象已经是代理对象,设置新的sql处理器。");
			((SqlProxyHandler) Proxy.getInvocationHandler(dySql)).setSqlHandler(sqlHandler);
		} else {
			log.debug("创建Sql的代理对象!");
			final SqlProxyHandler sqlProxyHandler = new SqlProxyHandler(dySql, sqlHandler);
			final Class sqlClass = dySql.getClass();
			final Sql proxy = (Sql) Proxy.newProxyInstance(sqlClass.getClassLoader(), sqlClass.getInterfaces(), sqlProxyHandler);
			mappedStatement.setSql(proxy);
		}
	}
	try {
		return smc.queryForList(statementId, param);
	} catch (SQLException ex) {
		throw new RuntimeException("查询失败", ex);
	}
}
private static final class SqlProxyHandler implements InvocationHandler {

	private final Sql sql;
	private final ThreadLocal<SqlHandler> sqlHandler = new ThreadLocal();

	public SqlProxyHandler(Sql sql, SqlHandler handler) {
		this.sql = sql;
		setSqlHandler(handler);
	}

	public Sql getSql() {
		return sql;
	}

	public void setSqlHandler(SqlHandler handler) {
		this.sqlHandler.set(handler);
	}

	public SqlHandler getSqlHandler() {
		return sqlHandler.get();
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result = method.invoke(getSql(), args);
		if ("getSql".equals(method.getName()) && getSqlHandler() != null) {
			log.debug("原SQL: " + result);
			final StatementScope statementScope = (StatementScope) args[0];
			final Object[] params = statementScope.getParameterMap().getParameterObjectValues(statementScope, args[1]);
			result = getSqlHandler().handle((String) result, params);
			log.debug("处理后: " + result);
			setSqlHandler(null);//执行完成后清除线程局部变量,下次调用需要设置新值,否则不拦截getSql方法
		}
		return result;
	}
}
interface SqlHandler {

	/**
	 * 处理sql语句
	 *
	 * @param sql ibatis生成的sql语句,其中参数用?号占位
	 * @param params sql对应的参数
	 * @return
	 * @throws Throwable
	 */
	String handle(String sql, Object[] params) throws Throwable;
}

© 著作权归作者所有

微凉的风
粉丝 3
博文 1
码字总数 680
作品 0
成都
程序员
私信 提问
加载中

评论(12)

i
itxx2016
推荐国内最流行的ibatis代码生成网站 --- fwjava.com
无需任何安装配置,直接在线生成,且十分规范好用.
现在,很多知名的互联网公司都在用它.
李__光

引用来自“李__光”的评论

麻烦问下楼主,能发源代码来看下么?具体类这些?

引用来自“刘家华”的评论

第一部分是代码调用的例子, 后面一部分代码就是实现, 所有需要的代码都在这里了

引用来自“李__光”的评论

mappedStatement.setSql(proxy);这句代码我这里报错, The method setSql(Sql) is undefined for the type MappedStatement 没有这个方法?

引用来自“刘家华”的评论

我用的ibatis-2.3.4.726.jar,是有这个方法的
楼主getSqlMapClient()你这个是写了什么?怎么获得的?
微凉的风
微凉的风 博主

引用来自“李__光”的评论

麻烦问下楼主,能发源代码来看下么?具体类这些?

引用来自“刘家华”的评论

第一部分是代码调用的例子, 后面一部分代码就是实现, 所有需要的代码都在这里了

引用来自“李__光”的评论

mappedStatement.setSql(proxy);这句代码我这里报错, The method setSql(Sql) is undefined for the type MappedStatement 没有这个方法?
我用的ibatis-2.3.4.726.jar,是有这个方法的
李__光

引用来自“李__光”的评论

麻烦问下楼主,能发源代码来看下么?具体类这些?

引用来自“刘家华”的评论

第一部分是代码调用的例子, 后面一部分代码就是实现, 所有需要的代码都在这里了
mappedStatement.setSql(proxy);这句代码我这里报错, The method setSql(Sql) is undefined for the type MappedStatement 没有这个方法?
李__光

引用来自“李__光”的评论

麻烦问下楼主,能发源代码来看下么?具体类这些?

引用来自“刘家华”的评论

第一部分是代码调用的例子, 后面一部分代码就是实现, 所有需要的代码都在这里了
麻烦问下StatementScope 这个是哪个包的?我的ibatis2.3.0里面没有这个类?
微凉的风
微凉的风 博主

引用来自“李__光”的评论

麻烦问下楼主,能发源代码来看下么?具体类这些?
第一部分是代码调用的例子, 后面一部分代码就是实现, 所有需要的代码都在这里了
李__光
麻烦问下楼主,能发源代码来看下么?具体类这些?
微凉的风
微凉的风 博主
SqlProxyHandler是我自定义的一个内部静态类,直接写在你的baseDao里就行,与queryWithSqlHandler方法在一个文件中就行
fuYi
fuYi
SqlProxyHandler 是哪个包下的
fuYi
fuYi
您好 楼主 我把你代码粘贴不能成功啊 SqlProxyHandler 这个类 不能有public 域或是static 前置修饰符,只能是final修饰
ibatis sqlMap 使用

SqlMap的配置是iBatis中应用的核心。这部分任务占据了iBatis开发的70的工作量。 1、命名空间: 在此空间外要引用此空间的元素,则需要加上命名空间名。 2、实体的别名: 如果有用到的全名的地...

为了美好的明天
2018/04/27
25
0
iBatis SqlMap的配备总结

iBatis SqlMap的配置总结 核心提示:SqlMap的配置是iBatis中应用的核心。这部分任务占据了iBatis开发的70的工作量。 1、命名空间: sqlMap namespace=Account,在此空间外要引用此空间的元素...

mjZhang
2014/04/30
224
1
深入分析 iBATIS 框架之系统架构与映射原理

简介: iBATIS 通过 SQL Map 将 Java 对象映射成 SQL 语句和将结果集再转化成 Java 对象,与其他 ORM 框架相比,既解决了 Java 对象与输入参数和结果集的映射,又能够让用户方便的手写使用 ...

老盖
2010/11/11
2.2K
3
凤凰涅槃:从 iBatis 到 MyBatis

简介: 本文主要讲述了 iBatis 2.x 和 MyBatis 3.0.x 的区别,以及从 iBatis 向 MyBatis 移植时需要注意的地方。通过对本文的学习,读者基本能够了解 MyBatis 有哪些方面的改进,并能够顺利使...

IBMdW
2011/06/24
1K
2
使用 ibatis 处理复杂对象数据关系的实例

ibatis 基本介绍 起源于 2001 年的开放源代码项目 ibatis,是一个基于 Java 的持久层框架。与 Hibernate, Toplink 等持久化框架不同,ibatis 是一个 “半自动化”的 ORM 实现。ibatis 没有对...

红薯
2010/09/05
1K
4

没有更多内容

加载失败,请刷新页面

加载更多

《Java并发编程的艺术》第二章--2.2--synchronized的实现原理与应用

在多线程并发编程中synchronized一直是元老级角色,很多人都会称呼它为重量级锁。但 是,随着Java SE 1.6对synchronized进行了各种优化之后,有些情况下它就并不那么重了 Java中的每一个对象...

我是警察叔叔
14分钟前
4
0
常见排序算法及对应的时间复杂度和空间复杂度

本人免费整理了Java高级资料,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高并发分布式等教程,一共30G,需要自己领取。 传送门:https://mp.weixin.qq.com/s/Jzdd...

李红欧巴
18分钟前
2
0
时间和空间的完美统一!阿里云时空数据库正式商业化

经过一段时间公测,得到广大客户的热烈支持,阿里云时空数据库已经于2019年9月10日正式商业化售卖! 产品介绍 时空数据库能够存储、管理包括时间序列以及空间地理位置相关的数据。我们的社会...

阿里云官方博客
22分钟前
3
0
什么是公有云、私有云和混合云云桌面,看完后涨知识了

前不久听到有用户在抱怨说“我就想部署个云桌面而已,怎么还有公有云、私有云和混合云这么个说法的,搞得我都混淆了”,那么到底什么是公有云、私有云和混合云云桌面的呢,他们的优缺点又是怎...

GZASD
25分钟前
4
0
6 个 K8s 日志系统建设中的典型问题,你遇到过几个?

导读:随着 K8s 不断更新迭代,使用 K8s 日志系统建设的开发者,逐渐遇到了各种复杂的问题和挑战。本篇文章中,作者结合自己多年经验,分析 K8s 日志系统建设难点,期待为读者提供有益参考。...

大涛学长
26分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部