如果MyBatis 3中where_in子句为空,我如何跳过查询?

时间:2017-03-24 09:19:58

标签: mybatis

select * from users where id in ()

查询如上所示。

<select id="getByIds" resultMap="BaseResultMap">
    SELECT
    <include refid="BaseColumnList"/>
    FROM users
    WHERE id IN
    <foreach item="id" collection="ids"
             open="(" separator="," close=")">
        #{id}
    </foreach>
</select>

如果Param ids为空,Mybatis将抛出BadSqlGrammarException,生成类似“select * from users where id in”的查询。

如果ids为空,我如何跳过查询并返回空列表?

4 个答案:

答案 0 :(得分:6)

  

如果ID为空,我如何跳过查询并返回空列表?

跳过查询(不执行),请不要拨打Mybatis。 调用代码应检查 ids 是否为空:

return null == ids || ids.isEmpty() ? new ArrayList<User>() : session.select("getByIds", ids);

这正是问题中提出的问题。

如果你真的希望Mybatis处理这个问题,那么生成的查询必须是有效的,因为必须执行(然后不要跳过)才能快速返回空结果 。这意味着忘记像id = <!-- a value that will never exist in the table -->这样的东西,因为它肯定会涉及(自由和无用的)全扫描来搜索未存在的值。 然后:

    WHERE 
    <choose>
        <when test="ids==null || ids.isEmpty()">
            1 = 0 <!-- a test returning false, to adapt depending on you DB vendor -->
        </when>
        <otherwise>
            id IN <foreach item="id" collection="ids" open="(" separator="," close=")">#{id}</foreach>
        </otherwise>
    </choose>

确认的另一个选择是使用拦截器来取消&#34;取消&#34;在执行之前的查询,但这肯定是在这里必须实现的内容的过度复杂。

答案 1 :(得分:2)

java代码功能

 List<ApiPriceChlogEntity> getApiAndDevPrice(@Param("apiKeys") List<String> currentApiKey, @Param("devKeys") List<String> currentDevKey, @Param("startDate") Date startDate);

映射器文件

<select id="getApiAndDevPrice"  resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List"/>
FROM t_api_price_chlog tab1
<where>
    <if test="apiKeys.size() > 0">
      tab1.api_key IN
      <foreach collection="apiKeys" item="item" separator="," open="(" close=")" index="">
        #{item}
      </foreach>
    </if>
    <if test="devKeys.size() > 0">
      AND tab1.dev_key IN
      <foreach collection="devKeys" item="item" separator="," open="(" close=")" index="">
        #{item}
      </foreach>
    </if>

    <if test="startDate != null">
      AND tab1.change_date >= #{startDate}
    </if>
</where>

我测试过,希望能帮到你。

答案 2 :(得分:0)

使用mybatis拦截器,创建一个n PreparedStatement对象,然后将其返回。

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),
    @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})})
@Slf4j
public class MyBatisInterceptor implements Interceptor {
   @Override
   public Object intercept(Invocation invocation) throws Throwable {
      //...your code
      //return invocation.proceed();
      return new NullExecutor();
   }
}

MyBatis要获取PreparedStatement对象作为返回值,“ NullExecutor”为:

public class NullExecutor implements PreparedStatement {}

什么都不做,只写几件事,就像:

@Override
public void setDouble(int parameterIndex, double x) throws SQLException {
    //empty here
}
@Override
public boolean execute() throws SQLException {
    //it's ok,do noting.
    return false;
}
...etc

添加您的配置:

@Bean
public MyBatisInterceptor myBatisInterceptor() {
    return new MyBatisInterceptor();
}

您需要在Interceptor中获取“ BoundSql”,然后才能获取sql和args,只需对其进行谷歌搜索即可。

我不确定它是否可以正常工作,只是为了学习。

答案 3 :(得分:-1)

使用测试:

<select id="getByIds" resultMap="BaseResultMap">
    SELECT
    <include refid="BaseColumnList"/>
    FROM users
<if test="ids!= null">
    WHERE id IN
    <foreach item="id" collection="ids"
             open="(" separator="," close=")">
        #{id}
    </foreach>
</if>
</select>