如何使用iBatis获取参数化查询-Spring

How to get parameterized query with iBatis-Spring

我正在开发一个集成了 spring-ibatis 的应用程序,我必须在其中记录一些执行的查询。所以我想做的,基本上是从 XML 配置文件中的 ibatis 映射语句中获取 SQL,然后以某种方式添加参数。我已经能够使用这行代码获得查询:

MappedStatement ms = (MappedStatement) ((SqlMapClientImpl) sqlMapClient)
    .getDelegate().getMappedStatement(queryId);

ms.setParameterClass(HashMap.class);
RequestScope scope = new RequestScope();
scope.setStatement(ms);

String sql = ((DynamicSql) ms.getSql()).getSql(scope, params);

所以在第一行我得到了 MappedStatement,在最后一行我得到了原始查询。问题是,即使我将带有查询参数的对象传递给它,SQL 仍然有参数占位符 '?' (在 XML 查询中,它们是命名参数,而不是位置参数)。

我曾尝试设置 parameterClass 字段而不是 here 建议的 parameterMap 但没有成功。我不确定如何使用内联参数。

我正在使用 ibatis-sqlmap 2.3.0spring-ibatis 2.0.8

您可能已经注意到,我对 iBatis 知之甚少。另外,我知道这很脏,我正在使用我不应该使用的 类,无需指出这一点。

感谢您的帮助。

我已经解决了这个问题,我想与未来可能遇到相同问题的读者分享解决方案。在这样做之前,请记住这不是您应该使用 iBatis 的方式,而只是获取底层 SQL.

的肮脏解决方法

首先,我们需要将 iBatis 查询至少分为 2 组:

  1. Static queries,它们是没有任何条件元素的简单映射语句。

  2. Dynamic queries,它们是带有条件元素的映射语句(例如isEqualisGreaterThanisNull...).

完成此差异后,这里是获取 SQL:

的代码
public static String getSQLFromDynamicQuery(SqlMapClient sqlMapClient,
        String queryId, Object paramObject) {

    // Gets the SQL and parameters.
    MappedStatement ms = ((SqlMapClientImpl) sqlMapClient).getDelegate()
            .getMappedStatement(queryId);
    RequestScope scope = new RequestScope();
    scope.setStatement(ms);
    String sql = ((DynamicSql) ms.getSql()).getSql(scope, paramObject);
    Object[] params = ms.getSql().getParameterMap(scope, paramObject)
            .getParameterObjectValues(scope, paramObject);

    // Adds params to the query.
    return bindQueryParam(sql, params);
}

public String getSQLFromStaticQuery(SqlMapClient sqlMapClient,
        String queryId, Object... params) {

    // Gets the SQL.
    String sql = ((StaticSql) ((SqlMapClientImpl) sqlMapClient)
            .getDelegate().getMappedStatement(queryId).getSql()).getSql(
            null, null);

    // Adds params to the query.
    if (params != null) {
        sql = bindQueryParam(sql, params);
    }

    return sql;
}

public static String bindQueryParam(String sql, Object... params) {
    String result = sql;
    for (Object param : params) {
        result = result.replaceFirst("\?",
                param == null ? "null" : param.toString());
    }
    return result;
}

bindQueryParam 方法将查询中的问号替换为对象数组。对于静态查询,您必须同时传递该数组,对于动态查询,您可以传递 Objectjava.util.Map,具体取决于映射语句的 parameterClass

这两种方法都使用显式子转换(我花了很多时间查看源代码来弄清楚如何使它像你想象的那样工作),所以你可能要注意调用正确的方法根据您正在处理的映射语句,否则您将得到 ClassCastException.

同样,这不是推荐的方法,但如果您需要它,它会起作用。