前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iBatis3基于方言(Dialect)

iBatis3基于方言(Dialect)

作者头像
py3study
发布2020-01-15 12:33:19
6790
发布2020-01-15 12:33:19
举报
文章被收录于专栏:python3python3

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

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

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

能够拦截的的类如下:

Java代码 收藏代码 Executor (update,query,flushStatements,commit,rollback,getTransaction,close,isClosed) ParameterHandler (getParameterObject,setParameters) ResultSetHandler (handleResultSets,handleOutputParameters) StatementHandler (prepare,parameterize,batch,update,query)

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

该方法完整是:

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

分页方言的基本实现:

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

Java代码 收藏代码 query("select * from user",5,10);

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

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

1.拦截类实现:

Java代码 收藏代码 @Intercepts({@Signature( type= Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})}) public class OffsetLimitInterceptor implements Interceptor{ static int MAPPED_STATEMENT_INDEX = 0; static int PARAMETER_INDEX = 1; static int ROWBOUNDS_INDEX = 2; static int RESULT_HANDLER_INDEX = 3;

代码语言:javascript
复制
Dialect dialect;  

public Object intercept(Invocation invocation) throws Throwable {  
    processIntercept(invocation.getArgs());  
    return invocation.proceed();  
}  

void processIntercept(final Object[] queryArgs) {  
    //queryArgs = query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler)  
    MappedStatement ms = (MappedStatement)queryArgs[MAPPED_STATEMENT_INDEX];  
    Object parameter = queryArgs[PARAMETER_INDEX];  
    final RowBounds rowBounds = (RowBounds)queryArgs[ROWBOUNDS_INDEX];  
    int offset = rowBounds.getOffset();  
    int limit = rowBounds.getLimit();  

    if(dialect.supportsLimit() && (offset != RowBounds.NO_ROW_OFFSET || limit != RowBounds.NO_ROW_LIMIT)) {  
        BoundSql boundSql = ms.getBoundSql(parameter);  
        String sql = boundSql.getSql().trim();  
        if (dialect.supportsLimitOffset()) {  
            sql = dialect.getLimitString(sql, offset, limit);  
            offset = RowBounds.NO_ROW_OFFSET;  
        } else {  
            sql = dialect.getLimitString(sql, 0, limit);  
        }  
        limit = RowBounds.NO_ROW_LIMIT;  

        queryArgs[ROWBOUNDS_INDEX] = new RowBounds(offset,limit);  
        BoundSql newBoundSql = new BoundSql(sql, boundSql.getParameterMappings(), boundSql.getParameterObject());  
        MappedStatement newMs = copyFromMappedStatement(ms, new BoundSqlSqlSource(newBoundSql));  
        queryArgs[MAPPED_STATEMENT_INDEX] = newMs;  
    }  
}  

private MappedStatement copyFromMappedStatement(MappedStatement ms,SqlSource newSqlSource) {  
    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());  
    builder.timeout(ms.getTimeout());  
    builder.parameterMap(ms.getParameterMap());  
    builder.resultMaps(ms.getResultMaps());  
    builder.cache(ms.getCache());  
    MappedStatement newMs = builder.build();  
    return newMs;  
}  

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

public void setProperties(Properties properties) {  
    String dialectClass = new PropertiesHelper(properties).getRequiredString("dialectClass");  
    try {  
        dialect = (Dialect)Class.forName(dialectClass).newInstance();  
    } catch (Exception e) {  
        throw new RuntimeException("cannot create dialect instance by dialectClass:"+dialectClass,e);  
    }   
    System.out.println(OffsetLimitInterceptor.class.getSimpleName()+".dialect="+dialectClass);  
}  

public static class BoundSqlSqlSource implements SqlSource {  
    BoundSql boundSql;  
    public BoundSqlSqlSource(BoundSql boundSql) {  
        this.boundSql = boundSql;  
    }  
    public BoundSql getBoundSql(Object parameterObject) {  
        return boundSql;  
    }  
}  

}

2.ibatis3配置文件内容:

Xml代码 收藏代码 <configuration> <plugins> <!-- 指定数据库分页方言Dialect, 其它方言:OracleDialect,SQLServerDialect,SybaseDialect,DB2Dialect,PostgreSQLDialect,MySQLDialect,DerbyDialect--> <plugin interceptor="cn.org.rapid_framework.ibatis3.plugin.OffsetLimitInterceptor"> <property name="dialectClass" value="cn.org.rapid_framework.jdbc.dialect.MySQLDialect"/> </plugin> </plugins>

代码语言:javascript
复制
<environments default="development">  
    <environment id="development">  
        <transactionManager type="JDBC" />  
        <dataSource type="POOLED">  
            <property name="driver" value="com.mysql.jdbc.Driver" />  
            <property name="url" value="jdbc:mysql://localhost:3306/test" />  
            <property name="username" value="root" />  
            <property name="password" value="123456" />  
        </dataSource>  
    </environment>  
</environments>  

<mappers>  
    <mapper resource="com/company/project/model/mapper/BlogMapper.xml" />  
</mappers>  

</configuration>

3.MysqlDialect实现

Java代码 收藏代码 public class MySQLDialect extends Dialect{

代码语言:javascript
复制
public boolean supportsLimitOffset(){  
    return true;  
}  

public boolean supportsLimit() {     
    return true;     
}    

public String getLimitString(String sql, int offset, int limit) {  
        return getLimitString(sql,offset,String.valueOf(offset),limit,String.valueOf(limit));  
}  

public String getLimitString(String sql, int offset,String offsetPlaceholder, int limit, String limitPlaceholder) {  
    if (offset > 0) {     
        return sql + " limit "+offsetPlaceholder+","+limitPlaceholder;   
    } else {     
        return sql + " limit "+limitPlaceholder;  
    }    
}     

}

其它数据库的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插件

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-07-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档