ibatis mysql分页查询语句_简单实现ibatis的物理分页

本文介绍了如何在Ibatis中通过实现SqlHandler接口,利用queryWithSqlHandler方法来实现物理分页,避免了对SqlExecutor的侵入性修改,并确保版本稳定性。示例代码展示了如何处理SQL,计算总记录数,以及构造分页SQL。
摘要由CSDN通过智能技术生成

一直以来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 = 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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值