Java 如何在mybatis中动态拦截和更改sql查询

Java 如何在mybatis中动态拦截和更改sql查询,java,sql,mybatis,Java,Sql,Mybatis,我使用mybatis在项目中执行sql查询。我需要在执行之前截取sql查询以动态应用一些更改。我读过关于@interoptor的文章,比如: @Intercepts({@Signature(type= Executor.class, method = "query", args = {...})}) public class ExamplePlugin implements Interceptor { public Object intercept(Invocation invocation

我使用mybatis在项目中执行sql查询。我需要在执行之前截取sql查询以动态应用一些更改。我读过关于@interoptor的文章,比如:

@Intercepts({@Signature(type= Executor.class, method = "query", args = {...})})
public class ExamplePlugin implements Interceptor {
  public Object intercept(Invocation invocation) throws Throwable {
    return invocation.proceed();
  }
  public Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }
  public void setProperties(Properties properties) {
  }
}

它确实会拦截执行,但无法更改sql查询,因为相应的字段不可写。我应该手动构建整个对象的新实例来替换sql查询吗?拦截查询执行以动态更改查询执行的正确位置在哪里?谢谢。

你可以考虑使用一个字符串模板库(如速度、把手、胡子)来帮助你


到目前为止,甚至还有MyBatis Velocity()可以帮助您为sql编写脚本。

根据您想要进行的更改,您可能需要使用MyBatis 3的功能。我希望它能帮助您:

@Intercepts( { @Signature(type = Executor.class, method = "query", args = {
        MappedStatement.class, Object.class, RowBounds.class,
        ResultHandler.class
    })
})
public class SelectCountSqlInterceptor2 implements Interceptor
{
    public static String COUNT = "_count";
    private static int MAPPED_STATEMENT_INDEX = 0;
    private static int PARAMETER_INDEX = 1;
    @Override
    public Object intercept(Invocation invocation) throws Throwable
    {
        processCountSql(invocation.getArgs());
        return invocation.proceed();
    }
    @SuppressWarnings("rawtypes")
    private void processCountSql(final Object[] queryArgs)
    {
        if (queryArgs[PARAMETER_INDEX] instanceof Map)
        {
            Map parameter = (Map) queryArgs[PARAMETER_INDEX];
            if (parameter.containsKey(COUNT))
            {
                MappedStatement ms = (MappedStatement) queryArgs[MAPPED_STATEMENT_INDEX];
                BoundSql boundSql = ms.getBoundSql(parameter);
                String sql = ms.getBoundSql(parameter).getSql().trim();
                BoundSql newBoundSql = new BoundSql(ms.getConfiguration(),
                                                    getCountSQL(sql), boundSql.getParameterMappings(),
                                                    boundSql.getParameterObject());
                MappedStatement newMs = copyFromMappedStatement(ms,
                                        new OffsetLimitInterceptor.BoundSqlSqlSource(newBoundSql));
                queryArgs[MAPPED_STATEMENT_INDEX] = newMs;
            }
        }
    }
    // see: MapperBuilderAssistant
    @SuppressWarnings({ "unchecked", "rawtypes" })
    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());
        // setStatementTimeout()
        builder.timeout(ms.getTimeout());
        // setParameterMap()
        builder.parameterMap(ms.getParameterMap());
        // setStatementResultMap()
        List<ResultMap> resultMaps = new ArrayList<ResultMap>();
        String id = "-inline";
        if (ms.getResultMaps() != null)
        {
            id = ms.getResultMaps().get(0).getId() + "-inline";
        }
        ResultMap resultMap = new ResultMap.Builder(null, id, Long.class,
                new ArrayList()).build();
        resultMaps.add(resultMap);
        builder.resultMaps(resultMaps);
        builder.resultSetType(ms.getResultSetType());
        // setStatementCache()
        builder.cache(ms.getCache());
        builder.flushCacheRequired(ms.isFlushCacheRequired());
        builder.useCache(ms.isUseCache());
        return builder.build();
    }
    private String getCountSQL(String sql)
    {
        String lowerCaseSQL = sql.toLowerCase().replace("\n", " ").replace("\t", " ");
        int index = lowerCaseSQL.indexOf(" order ");
        if (index != -1)
        {
            sql = sql.substring(0, index);
        }
        return "SELECT COUNT(*) from ( select 1 as col_c " + sql.substring(lowerCaseSQL.indexOf(" from "))  + " )   cnt";
    }
    @Override
    public Object plugin(Object target)
    {
        return Plugin.wrap(target, this);
    }
    @Override
    public void setProperties(Properties properties)
    {
    }
}
@拦截({@Signature(type=Executor.class,method=“query”,args={
MappedStatement.class、Object.class、RowBounds.class、,
ResultHandler.class
})
})
公共类SelectCountSqlInterceptor 2实现拦截器
{
公共静态字符串计数=“\u计数”;
私有静态int映射_语句_索引=0;
私有静态int参数_INDEX=1;
@凌驾
公共对象拦截(调用)抛出可丢弃的
{
processCountSql(invocation.getArgs());
返回调用。继续();
}
@抑制警告(“原始类型”)
私有void processCountSql(最终对象[]queryArgs)
{
if(queryArgs[参数索引]映射实例)
{
Map参数=(Map)queryArgs[参数_索引];
if(参数containsKey(计数))
{
MappedStatement ms=(MappedStatement)queryArgs[映射的语句索引];
BoundSql BoundSql=ms.getBoundSql(参数);
字符串sql=ms.getBoundSql(参数).getSql().trim();
BoundSql newBoundSql=新的BoundSql(ms.getConfiguration(),
getCountSQL(sql),boundSql.getParameterMappings(),
boundSql.getParameterObject());
MappedStatement newMs=copyFromMappedStatement(ms,
新的offsetlimitterceptor.boundsqlsource(newBoundSql));
queryArgs[MAPPED_STATEMENT_INDEX]=newMs;
}
}
}
//请参阅:MapperBuilderAsistant
@SuppressWarnings({“unchecked”,“rawtypes”})
私有MappedStatement copyFromMappedStatement(MappedStatement ms,
SqlSource新闻(SqlSource)
{
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());
//setStatementTimeout()
超时(ms.getTimeout());
//setParameterMap()
builder.parameterMap(ms.getParameterMap());
//setStatementResultMap()
List resultmap=new ArrayList();
字符串id=“-inline”;
如果(ms.getResultMaps()!=null)
{
id=ms.getResultMaps().get(0.getId()+“-inline”;
}
ResultMap ResultMap=new ResultMap.Builder(null,id,Long.class,
新建ArrayList()).build();
结果映射。添加(结果映射);
builder.resultmap(resultmap);
builder.resultsetype(ms.getresultsetype());
//setStatementCache()
builder.cache(ms.getCache());
builder.flushCacheRequired(ms.isFlushCacheRequired());
builder.useCache(ms.isUseCache());
返回builder.build();
}
私有字符串getCountSQL(字符串sql)
{
String lowerCaseSQL=sql.toLowerCase().replace(“\n”,”).replace(“\t”,”);
int index=小写的ql.indexOf(“顺序”);
如果(索引!=-1)
{
sql=sql.substring(0,索引);
}
返回“SELECT COUNT(*)from(选择1作为列c)+sql.substring(小写sql.indexOf(“from”)+”)cnt”;
}
@凌驾
公共对象插件(对象目标)
{
返回Plugin.wrap(target,this);
}
@凌驾
公共void集合属性(属性)
{
}
}

您有这样的例子吗?我觉得这份文件没有多大用处