我有一个正在工作的 postgres 查询,我试图在 Mybatis 中设置它,但不断收到语法错误。我想在 Mybatis 中实现的 PgAdmin 中运行的查询检查两个数组之间是否存在任何公共项。我的 pgAdmin 中的工作查询如下:
SELECT * FROM weather_schema.weather weather
WHERE STRING_TO_ARRAY(weather.phenoms, ',') && '{"TO", "WI"}'```
现在下面是我如何在 Mybatis xml Mapper 中进行此设置,其中 '{"TO", "WI"}' 被称为“phenoms”的可注入字符串列表替换。
<select id="getFilteredWeather" resultMap="WeatherObj">
SELECT
*
FROM weather_schema.weather weather
WHERE
string_to_array(weather.custom_phenoms, ',') &&
<foreach item="phenom" index="," collection="phenoms"
open="'{"" separator="","" close=""}'">
#{phenom}
</foreach>
</select>
这给出了以下结果:
org.mybatis.spring.MyBatisSystemException\] with root cause
org.postgresql.util.PSQLException: The column index is out of range: 7, number of columns: 6.
#{}
是准备好的语句中的占位符,因此不能在文字中使用它。
虽然在技术上可以使用
${}
而不是 #{}
来生成这样的文字,但不建议这样做,因为这样很难防止 SQL 注入(请参阅此 FAQ 条目)。
我将向您展示三种替代解决方案。
STRING_TO_ARRAY
ARRAY[...]::TEXT[]
语法STRING_TO_ARRAY
关于如何使用连接的
phenoms
,可能有一些选项。WhetherObj
添加一个新方法。
public String getPhenomsStr() {
return String.join(",", phenoms);
}
那么映射器中的
WHERE
子句将如下所示。
WHERE
string_to_array(weather.custom_phenoms, ',') &&
string_to_array(#{phenomsStr} ',')
ARRAY[...]::TEXT[]
语法这个想法与你原来的解决方案类似。
WHERE
string_to_array(weather.custom_phenoms, ',') &&
string_to_array(
<foreach item="phenom" collection="phenoms"
open="ARRAY[" separator="," close="]::TEXT[]">
#{phenom}
</foreach>
您可以编写一个调用
Statement#setArray()
的自定义类型处理程序。
import java.sql.Array;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
public class StringListTypeHandler extends BaseTypeHandler<List<String>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<String> parameter, JdbcType jdbcType)
throws SQLException {
Array array = ps.getConnection().createArrayOf("TEXT", parameter.toArray());
ps.setArray(i, array);
array.free();
}
// ...
}
注意:此类型处理程序的完整实现位于此可执行文件demo中。
然后,您可以在参数引用中指定类型处理程序。
WHERE
string_to_array(weather.custom_phenoms, ',') &&
#{phenoms,typeHandler=my.pkg.StringListTypeHandler}