如果 where_in 子句在 MyBatis 3 中为空,如何跳过查询?
How can I skip query if where_in clause is empty in MyBatis 3?
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>
如果参数ids
为空,Mybatis会抛出BadSqlGrammarException异常,生成类似'select * from users where id in
'的查询。
如果 ids
为空,我如何跳过查询和 return 空列表?
使用测试:
<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>
How can I skip query and return empty list if ids is empty?
要跳过查询(不执行),只要不调用Mybatis即可。
调用代码应检查 ids 是否为空:
return null == ids || ids.isEmpty() ? new ArrayList<User>() : session.select("getByIds", ids);
这正是问题中提出的问题。
如果你真的想让 Mybatis 处理这个,那么生成的查询必须是有效的,因为必须执行(然后不跳过)到 return 空结果 快速 。这意味着忘记像 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>
确认的另一种选择是在查询执行前使用拦截器 "cancel" 查询,但这对于此处必须实现的目标来说绝对是过大的复杂性。
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>
我已经测试过了,希望能帮到你。
使用 mybatis 拦截器,创建一个 nil PreparedStatement 对象并 return 它。
@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 对象作为 return 值,"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,就google即可。
不知道能不能用,学习一下
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>
如果参数ids
为空,Mybatis会抛出BadSqlGrammarException异常,生成类似'select * from users where id in
'的查询。
如果 ids
为空,我如何跳过查询和 return 空列表?
使用测试:
<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>
How can I skip query and return empty list if ids is empty?
要跳过查询(不执行),只要不调用Mybatis即可。 调用代码应检查 ids 是否为空:
return null == ids || ids.isEmpty() ? new ArrayList<User>() : session.select("getByIds", ids);
这正是问题中提出的问题。
如果你真的想让 Mybatis 处理这个,那么生成的查询必须是有效的,因为必须执行(然后不跳过)到 return 空结果 快速 。这意味着忘记像 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>
确认的另一种选择是在查询执行前使用拦截器 "cancel" 查询,但这对于此处必须实现的目标来说绝对是过大的复杂性。
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>
我已经测试过了,希望能帮到你。
使用 mybatis 拦截器,创建一个 nil PreparedStatement 对象并 return 它。
@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 对象作为 return 值,"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,就google即可。
不知道能不能用,学习一下