Grails插件MyBatis分页设计

新的MyBatis比老的Ibatis有了个新的东东Plugin,在配置文件中

<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>

<plugins>
<plugin interceptor="store.MySqlPaginationPlugin"/>
</plugins>
</configuration>

有了这个插件设计,就不用在那么麻烦的按照老的Ibatis的方式设计分页了,只需按照MyBatis要求的插件方式来拦截sql修改成分页形式了
先弄个基类,共享代码,支持所有的数据库,将不同的东西分离出来

Intercepts({@Signature(type = Executor.class, method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public abstract class PaginationBasePlugin implements Interceptor {

public Object intercept(Invocation invocation) throws Throwable {
Object[] queryArgs = invocation.getArgs();
MappedStatement ms = (MappedStatement) queryArgs[0];
BoundSql boundSql = ms.getBoundSql(queryArgs[1]);
String sql = boundSql.getSql().trim();

Object args = queryArgs[1];

sql = paginationSql(sql,args); //通过子类实现
BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), sql, boundSql.getParameterMappings(), boundSql.getParameterObject());

MappedStatement newMs = copyFromMappedStatement(ms, new BoundSqlSqlSource(newBoundSql));
queryArgs[0] = newMs;
return invocation.proceed();
}
protected abstract String paginationSql(String sql,Object args); //子类实现
//see: MapperBuilderAssistant
private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());

builder.resource(ms.getResource());
builder.fetchSize(ms.getFetchSize());
builder.statementType(ms.getStatementType());
builder.keyGenerator(ms.getKeyGenerator());
builder.keyProperty(ms.getKeyProperty());

//setStatementTimeout()
builder.timeout(ms.getTimeout());

//setStatementResultMap()
builder.parameterMap(ms.getParameterMap());

//setStatementResultMap()
builder.resultMaps(ms.getResultMaps());
builder.resultSetType(ms.getResultSetType());

//setStatementCache()
builder.cache(ms.getCache());
builder.flushCacheRequired(ms.isFlushCacheRequired());
builder.useCache(ms.isUseCache());

return builder.build();
}

public static class BoundSqlSqlSource implements SqlSource {

private BoundSql boundSql;

public BoundSqlSqlSource(BoundSql boundSql) {
this.boundSql = boundSql;
}

public BoundSql getBoundSql(Object parameterObject) {
return boundSql;
}
}

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

public void setProperties(Properties properties) {
//suffix = properties.get("dirname").toString();
}
}


以MySql数据库分页举例,做一个MySqlPaginationPlugin


@Intercepts({@Signature(type = Executor.class, method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class MySqlPaginationPlugin extends PaginationBasePlugin {
@Override
protected String paginationSql(String sql,Object args) {
if(args instanceof Map){
if(((Map) args).containsKey("pagination")){
Map map = (Map) args;
RowBounds rowBounds = (RowBounds) map.get("pagination");
sql = sql+" limit " + rowBounds.getOffset()+ ","+rowBounds.getLimit(); //分页了
}
}
return sql;
}
}


MySql的分页比较简单,其他数据库的分页要求对sql参数进行分离和复杂点的修改,这些玩意大家自己就会倒腾了,网上有很多代码,再次不弄了

用法如下,从代码中可以看出,只要Xml Mapper的Sql语句输入参数为map类型,并且里面含有pagination键值就可以了,否则不分页

class ClientGateway {
static forceAsListOps = ["selectClient"];

def queryClient(RowBounds rowBounds) {
HashMap map = new HashMap()
map.put("pagination", rowBounds); //关键标志
sqlMapper.selectList("selectClient", map);
}
}

pagination的值为一个RowBounds类型,这个是MyBatis里面带的东西,我就直接拿来用了,反正就那两个属性offset,limit
这样同一个sql语句既可以支持分页也可以不支持分页,避免了写两套相同的sql,不好维护

<mapper namespace="client">
<select id="selectClient" parameterType="map" resultType="client">
select * from client
</select>
</mapper>

那么其中这个sql语句的count又如何不写两套sql弄出来呢?
同样道理,自己在map里面再加个特殊的标记,就可以一个sql语句也支持count了
综上,通过MyBatis的插件拦截sql是一个sql语句既可以直接执行,也可以支持分页和获取所有行数。提高了可维护性。
代码中的pagination字符串自己弄成常量吧,不满意的地方可以自己修改,思路就是这样了,我使着挺好用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值